-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #13 from databio/docs
dev
- Loading branch information
Showing
10 changed files
with
237 additions
and
62 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,93 +1,130 @@ | ||
# Package logmuse Documentation | ||
|
||
## Class AbsentOptionException | ||
<script> | ||
document.addEventListener('DOMContentLoaded', (event) => { | ||
document.querySelectorAll('h3 code').forEach((block) => { | ||
hljs.highlightBlock(block); | ||
}); | ||
}); | ||
</script> | ||
|
||
<style> | ||
h3 .lucidoc{ | ||
padding-left: 22px; | ||
text-indent: -15px; | ||
} | ||
h3 .hljs .lucidoc{ | ||
padding-left: 20px; | ||
margin-left: 0px; | ||
text-indent: -15px; | ||
martin-bottom: 0px; | ||
} | ||
h4 .lucidoc, table .lucidoc, p .lucidoc, li .lucidoc { margin-left: 30px; } | ||
h4 .lucidoc { | ||
font-style: italic; | ||
font-size: 1em; | ||
margin-bottom: 0px; | ||
} | ||
|
||
</style> | ||
<div class='lucidoc'> | ||
|
||
# Package `logmuse` Documentation | ||
|
||
## <a name="AbsentOptionException"></a> Class `AbsentOptionException` | ||
Exception subtype suggesting that client should add log options. | ||
|
||
|
||
### add\_logging\_options | ||
Augment a CLI argument parser with this package's logging options. | ||
```python | ||
def add_logging_options(parser) | ||
def init_logger(name='', level=None, stream=None, logfile=None, make_root=None, propagate=False, silent=False, devmode=False, verbosity=None, fmt=None, datefmt=None, plain_format=False, style=None) | ||
``` | ||
|
||
**Parameters:** | ||
Establish and configure primary logger. | ||
|
||
This is intended to be called just once per "session", with a "session" | ||
defined as an invocation of the main workflow, a testing session, or an | ||
import of the primary abstractions, e.g. in an interactive iPython session. | ||
#### Parameters: | ||
|
||
- `name` (`str`): name for the logger | ||
- `level` (`int | str`): minimal level of messages to listen for | ||
- `stream` (`str`): standard stream to use as log destination. The defaultbehavior is to write logs to stdout, even if null is passed here. This is to allow a CLI argument as input to stream parameter, where it may be undesirable to require specification of a default value in the client application in order to prevent passing None if no CLI option value is given. To disable standard stream logging, set 'silent' to True or pass a path to a file to which to write logs, which gets priority over a standard stream as the destination for log messages. | ||
- `logfile` (`str | FileIO[str]`): path to filesystem location to use aslogs destination. if provided, this mutes standard stream logging. | ||
- `make_root` (`bool`): whether to use returned logger as root logger. Thismeans the name will be 'root' and that messages will not propagate. | ||
- `propagate` (`bool`): whether to allow messages from this logger to reachparent logger(s). | ||
- `silent` (`bool`): whether to silence logging; this is only guaranteed formessages from this logger and for those from loggers beneath this one in the runtime hierarchy without no separate handling. Propagation must also be turned off separately--if this is not the root logger--in order to ensure that messages are not handled and emitted from a potential parent to the logger built here. | ||
- `devmode` (`bool`): whether to log in development mode; possibly amongother behavioral changes to logs handling, use a more information-rich message format template. | ||
- `verbosity` (`int | str`): alternate mode of expression for logging levelthat better accords with intuition about how to convey this. It's positively associated with message volume rather than negatively so, as logging level is. This takes precedence over 'level' if both are present. | ||
- `fmt` (`str`): message format/template. | ||
- `datefmt` (`str`): format/template for time component of a log record. | ||
- `plain_format` (`bool`): force use of plain message format, even ifin development mode (debug level) | ||
- `style` (`str`): string indicating message formatting strategy; refer tohttps://docs.python.org/3/howto/logging-cookbook.html#use-of-alternative-formatting-styles; only valid in Python3.2+ | ||
|
||
- `parser` -- `argparse.ArgumentParser`: CLI options and argument parser toaugment with logging options. | ||
|
||
#### Returns: | ||
|
||
**Returns:** | ||
- `logging.Logger`: configured Logger instance | ||
|
||
|
||
#### Raises: | ||
|
||
- `ValueError`: if attempting to name explicitly non-root logger witha root name, or if both level and verbosity are specified | ||
|
||
|
||
|
||
|
||
```python | ||
def setup_logger(name='', level=None, stream=None, logfile=None, make_root=None, propagate=False, silent=False, devmode=False, verbosity=None, fmt=None, datefmt=None, plain_format=False, style=None) | ||
``` | ||
|
||
`argparse.ArgumentParser`: the input argument, supplemented with thispackage's logging options. | ||
Old alias for init_logger for backwards compatibility | ||
|
||
|
||
|
||
```python | ||
def logger_via_cli(opts, strict=True, **kwargs) | ||
``` | ||
|
||
### logger\_via\_cli | ||
Convenience function creating a logger. | ||
|
||
This module provides the ability to augment a CLI parser with | ||
logging-related options/arguments so that client applications do not need | ||
intimate knowledge of the implementation. This function completes that | ||
lack of burden, parsing values for the options supplied herein. | ||
```python | ||
def logger_via_cli(opts, **kwargs) | ||
``` | ||
|
||
**Parameters:** | ||
#### Parameters: | ||
|
||
- `opts` -- `argparse.Namespace`: command-line options/arguments. | ||
- `opts` (`argparse.Namespace`): command-line options/arguments. | ||
- `strict` (`bool`): whether to raise an exception | ||
|
||
|
||
**Returns:** | ||
#### Returns: | ||
|
||
`logging.Logger`: configured logger instance. | ||
- `logging.Logger`: configured logger instance. | ||
|
||
|
||
**Raises:** | ||
#### Raises: | ||
|
||
- `pararead.logs.AbsentOptionException`: if one of the expected optionsisn't available in the given Namespace. Such a case suggests that a client application didn't use this module to add the expected logging options to a parser. | ||
- `pararead.logs.AbsentOptionException`: if one of the expected optionsisn't available in the given Namespace, and the argument to the strict parameter is True. Such a case suggests that a client application didn't use this module to add the expected logging options to a parser. | ||
|
||
|
||
|
||
|
||
### setup\_logger | ||
Establish and configure primary logger. | ||
|
||
This is intended to be called just once per "session", with a "session" | ||
defined as an invocation of the main workflow, a testing session, or an | ||
import of the primary abstractions, e.g. in an interactive iPython session. | ||
```python | ||
def setup_logger(name='', level=None, stream=None, logfile=None, make_root=None, propagate=False, silent=False, devmode=False, verbosity=None, fmt=None, datefmt=None, plain_format=False, style=None) | ||
def add_logging_options(parser) | ||
``` | ||
|
||
**Parameters:** | ||
|
||
- `name` -- `str`: name for the logger | ||
- `level` -- `int | str`: minimal level of messages to listen for | ||
- `stream` -- `str`: standard stream to use as log destination. The defaultbehavior is to write logs to stdout, even if null is passed here. This is to allow a CLI argument as input to stream parameter, where it may be undesirable to require specification of a default value in the client application in order to prevent passing None if no CLI option value is given. To disable standard stream logging, set 'silent' to True or pass a path to a file to which to write logs, which gets priority over a standard stream as the destination for log messages. | ||
- `logfile` -- `str | FileIO[str]`: path to filesystem location to use aslogs destination. if provided, this mutes standard stream logging. | ||
- `make_root` -- `bool`: whether to use returned logger as root logger. Thismeans the name will be 'root' and that messages will not propagate. | ||
- `propagate` -- `bool`: whether to allow messages from this logger to reachparent logger(s). | ||
- `silent` -- `bool`: whether to silence logging; this is only guaranteed formessages from this logger and for those from loggers beneath this one in the runtime hierarchy without no separate handling. Propagation must also be turned off separately--if this is not the root logger--in order to ensure that messages are not handled and emitted from a potential parent to the logger built here. | ||
- `devmode` -- `bool`: whether to log in development mode; possibly amongother behavioral changes to logs handling, use a more information-rich message format template. | ||
- `verbosity` -- `int | str`: alternate mode of expression for logging levelthat better accords with intuition about how to convey this. It's positively associated with message volume rather than negatively so, as logging level is. This takes precedence over 'level' if both are present. | ||
- `fmt` -- `str`: message format/template. | ||
- `datefmt` -- `str`: format/template for time component of a log record. | ||
- `plain_format` -- `bool`: force use of plain message format, even ifin development mode (debug level) | ||
- `style` -- `str`: string indicating message formatting strategy; refer tohttps://docs.python.org/3/howto/logging-cookbook.html#use-of-alternative-formatting-styles; only valid in Python3.2+ | ||
|
||
Augment a CLI argument parser with this package's logging options. | ||
#### Parameters: | ||
|
||
**Returns:** | ||
- `parser` (`argparse.ArgumentParser`): CLI options and argument parser toaugment with logging options. | ||
|
||
`logging.Logger`: configured Logger instance | ||
|
||
#### Returns: | ||
|
||
**Raises:** | ||
- `argparse.ArgumentParser`: the input argument, supplemented with thispackage's logging options. | ||
|
||
- `ValueError`: if attempting to name explicitly non-root logger witha root name, or if both level and verbosity are specified | ||
|
||
|
||
|
||
</div> | ||
|
||
|
||
**Version Information**: `logmuse` v0.1, generated by `lucidoc` v0.3.1 | ||
*Version Information: `logmuse` v0.2.1, generated by `lucidoc` v0.4.0* |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
# Using logmuse interactively | ||
|
||
|
||
To set logmuse to DEBUG while in an interactive session, use: | ||
|
||
``` | ||
logmuse.init_logger(PACKAGE, "DEBUG", devmode=True) | ||
``` | ||
|
||
For example, for package divvy, which uses logmuse, run this in your interactive session: | ||
|
||
``` | ||
logmuse.init_logger("divvy", "DEBUG", devmode=True) | ||
``` | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,100 @@ | ||
# Tutorial | ||
|
||
You are producing a CLI package that will use logmuse. Logmuse will provide command-line options to control logging, such as `--verbosity` and `--silent`. Here's how to set it up. | ||
|
||
## Imported packages | ||
|
||
For any packages that are imported by your CLI package, all you have to do is follow the normal usage of the built-in `logging` module. **No need to use logmuse in imported packages**. Just type, for example, something like: | ||
|
||
``` | ||
_LOGGER = logging.getLogger(__name__) | ||
``` | ||
|
||
At the top of each module, and then use `_LOGGER.debug` or whatever in the module. That's it. The command line arguments passed via your CLI will control the imported packages as well. Make sure your package isn't making a root logger or something silly like that. | ||
|
||
|
||
## Your CLI package | ||
|
||
Now, to use logmuse in your CLI package, *including* all imported loggers, all you have to do is: | ||
|
||
## 1 Initialize | ||
|
||
Just add to the `__init__.py` file: | ||
|
||
``` | ||
import logmuse | ||
logmuse.init_logger(PACKAGE) | ||
``` | ||
|
||
Where `PACKAGE` is the name of your package. Now it will be set up with default parameters for your within-python-use. Remember, **this is only for the CLI package.** Do not add this code to client packages that do not implement CLIs. | ||
|
||
|
||
## 2 Add CLI args | ||
|
||
When you build your argparser, add the logmuse CLI options with this: | ||
|
||
|
||
``` | ||
parser = logmuse.add_logging_options(parser) | ||
``` | ||
|
||
This will give you: | ||
|
||
- `--verbosity` | ||
- `--silent` | ||
- `--logdev` | ||
|
||
And your logger will automatically respond to these command-line arguments. (PS, [pypiper](http://pypiper.databio.org) uses logmuse to add these; so if you're using pypiper to add args, don't repeat). | ||
|
||
|
||
## 3 Activate logmuse | ||
|
||
At the top of your module file, say: | ||
|
||
``` | ||
import logmuse | ||
``` | ||
|
||
In your `main` function say: | ||
|
||
``` | ||
global _LOGGER | ||
_LOGGER = logmuse.logger_via_cli(args, make_root=True) | ||
``` | ||
|
||
Here, `args` is the result of argparse.parse_args(). | ||
|
||
|
||
|
||
|
||
## Old way | ||
|
||
No need to read further. This is how it *used to* work, before it was awesome. | ||
|
||
``` | ||
# Set the logging level. | ||
if args.dbg: | ||
# Debug mode takes precedence and will listen for all messages. | ||
level = args.logging_level or logging.DEBUG | ||
elif args.verbosity is not None: | ||
# Verbosity-framed specification trumps logging_level. | ||
level = _LEVEL_BY_VERBOSITY[args.verbosity] | ||
else: | ||
# Normally, we're not in debug mode, and there's no verbosity. | ||
level = LOGGING_LEVEL | ||
# Establish the project-root logger and attach one for this module. | ||
logger_kwargs = {"level": level, "logfile": args.logfile, "devmode": args.dbg} | ||
init_logger(name="peppy", **logger_kwargs) | ||
init_logger(name="divvy", **logger_kwargs) | ||
global _LOGGER | ||
_LOGGER = init_logger(name=_PKGNAME, **logger_kwargs) | ||
logger_kwargs = {"level": level, "logfile": args.logfile, "devmode": args.dbg} | ||
init_logger(name="peppy", **logger_kwargs) | ||
init_logger(name="divvy", **logger_kwargs) | ||
``` | ||
|
||
We should move the logging level stuff into logmuse |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,3 @@ | ||
from .est import * | ||
from ._version import __version__ | ||
from .est import LEVEL_BY_VERBOSITY, DEV_LOGGING_FMT |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1 @@ | ||
__version__ = "0.2.1" | ||
__version__ = "0.2.2" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -17,11 +17,12 @@ | |
__email__ = "[email protected]" | ||
|
||
__all__ = ["add_logging_options", "logger_via_cli", "init_logger", | ||
"setup_logger", "AbsentOptionException"] | ||
"setup_logger", "AbsentOptionException", "LOGGING_CLI_OPTDATA"] | ||
|
||
|
||
BASIC_LOGGING_FORMAT = "%(message)s" | ||
DEV_LOGGING_FMT = "[%(asctime)s] {%(name)s:%(lineno)d} (%(funcName)s) [%(levelname)s] > %(message)s " | ||
DEV_LOGGING_FMT = "%(levelname).4s %(asctime)s | %(name)s:%(module)s:%(lineno)d > %(message)s " | ||
DEFAULT_DATE_FMT = "%H:%M:%S" | ||
PACKAGE_NAME = "logmuse" | ||
STREAMS = {"OUT": sys.stdout, "ERR": sys.stderr} | ||
DEFAULT_STREAM = STREAMS["ERR"] | ||
|
@@ -30,9 +31,9 @@ | |
TRACE_LEVEL_VALUE = 5 | ||
TRACE_LEVEL_NAME = "TRACE" | ||
CUSTOM_LEVELS = {TRACE_LEVEL_NAME: TRACE_LEVEL_VALUE} | ||
SILENCE_LOGS_OPTNAME = "--silent" | ||
VERBOSITY_OPTNAME = "--verbosity" | ||
DEVMODE_OPTNAME = "--logdev" | ||
SILENCE_LOGS_OPTNAME = "silent" | ||
VERBOSITY_OPTNAME = "verbosity" | ||
DEVMODE_OPTNAME = "logdev" | ||
PARAM_BY_OPTNAME = {DEVMODE_OPTNAME: "devmode"} | ||
|
||
# Translation of verbosity into logging level. | ||
|
@@ -70,7 +71,7 @@ def add_logging_options(parser): | |
package's logging options. | ||
""" | ||
for optname, optdata in LOGGING_CLI_OPTDATA.items(): | ||
parser.add_argument("{}".format(optname), **optdata) | ||
parser.add_argument("--{}".format(optname), **optdata) | ||
return parser | ||
|
||
|
||
|
@@ -115,7 +116,7 @@ def logger_via_cli(opts, strict=True, **kwargs): | |
def init_logger( | ||
name="", level=None, stream=None, logfile=None, | ||
make_root=None, propagate=False, silent=False, devmode=False, | ||
verbosity=None, fmt=None, datefmt=None, plain_format=False, style=None): | ||
verbosity=None, fmt=None, datefmt=DEFAULT_DATE_FMT, plain_format=False, style=None): | ||
""" | ||
Establish and configure primary logger. | ||
|
@@ -317,3 +318,18 @@ def __init__(self, missing_optname): | |
format(missing_optname, "{}.{}".format( | ||
__name__, add_logging_options.__name__)) | ||
super(AbsentOptionException, self).__init__(likely_reason) | ||
|
||
|
||
|
||
|
||
# Stolen from peppy. Probably need to make peppy/looper rely on this. | ||
def get_logger(name): | ||
""" | ||
Return a logger with given name, equipped with custom method. | ||
:param str name: name for the logger to get/create. | ||
:return logging.Logger: named, custom logger instance. | ||
""" | ||
l = logging.getLogger(name) | ||
l.whisper = lambda msg, *args, **kwargs: l.log(5, msg, *args, **kwargs) | ||
return l |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.