Skip to content

Commit

Permalink
Merge pull request #17 from lifeomic/FLDM-390/json-child-logger
Browse files Browse the repository at this point in the history
Add JsonLogger which supports child loggers
  • Loading branch information
epeters3 authored Oct 11, 2024
2 parents 9e08f31 + f4b3700 commit 08f9933
Show file tree
Hide file tree
Showing 6 changed files with 249 additions and 100 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -129,3 +129,4 @@ dmypy.json
# Pyre type checker
.pyre/
.idea
.tool-versions
30 changes: 30 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# Changelog

All notable changes to this project will be documented in this file.

The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
and this project adheres to
[Semantic Versioning](http://semver.org/spec/v2.0.0.html).

## [Unreleased]

## [0.4.0] - 2024-10-11

### Added

- Added a new `JsonLogger` class that logs messages in JSON format. Supports
child loggers as well. The logger inherits from builtin `logging.Logger` and
the log methods have the same API as the builtin as well. Example usage:

```python
from lifeomic_logging import JsonLogger

# Create a logger with a name and optional context that will be included
# on all log messages.
logger = JsonLogger("my-logger", {"foo": "bar"})
logger.info({"msg": "message", "isTrue": True})
# >>> {"name": "my-logger", "foo": "bar", "level": "INFO", "msg": "message", "isTrue": true}
child_logger = logger.child({"fizz": "buzz"})
child.info("message")
# >>> {"name": "my-logger", "foo": "bar", "fizz": "buzz", "level": "INFO", "msg": "message"}
```
29 changes: 22 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,19 +11,23 @@

### Dependencies

* [Python 3](https://www.python.org/download/releases/3.0/) version >= 3.6
- [Python 3](https://www.python.org/download/releases/3.0/) version >= 3.6

### Getting the Source

This project is [hosted on GitHub](https://github.com/lifeomic/logging-py). You can clone this project directly using this command:
This project is [hosted on GitHub](https://github.com/lifeomic/logging-py). You
can clone this project directly using this command:

```bash
git clone git@github.com:lifeomic/logging-py.git
```

### Development

Python environments are managed using [virtualenv](https://virtualenv.pypa.io/en/latest/). Be sure to have this installed first `pip install virtualenv`. The makefile will setup the environment for the targets listed below.
Python environments are managed using
[virtualenv](https://virtualenv.pypa.io/en/latest/). Be sure to have this
installed first `pip install virtualenv`. The makefile will setup the
environment for the targets listed below.

#### Running tests

Expand Down Expand Up @@ -54,20 +58,31 @@ with scoped_logger(__name__, { "bar": "foo" }) as log:

## Release Process

[Releases](https://github.com/lifeomic/logging-py/releases) are generally created with each merged PR. Packages for each release are published to [PyPi](https://pypi.org/project/phc/). See [CHANGELOG.md](CHANGELOG.md) for release notes.
[Releases](https://github.com/lifeomic/logging-py/releases) are generally
created with each merged PR. Packages for each release are published to
[PyPi](https://pypi.org/project/phc/). See [CHANGELOG.md](CHANGELOG.md) for
release notes.

To release a new version of the package, update the version number in
`lifeomic_logging/version.py` as a part of your change, and the new version will
be released automatically to PyPi on merge.

### Versioning

This project uses [Semantic Versioning](http://semver.org/).

## Contributing

We encourage public contributions! Please review [CONTRIBUTING.md](CONTRIBUTING.md) and [CODE_OF_CONDUCT.md](CODE_OF_CONDUCT.md) for details on our code of conduct and development process.
We encourage public contributions! Please review
[CONTRIBUTING.md](CONTRIBUTING.md) and [CODE_OF_CONDUCT.md](CODE_OF_CONDUCT.md)
for details on our code of conduct and development process.

## License

This project is licensed under the MIT License - see [LICENSE](LICENSE) file for details.
This project is licensed under the MIT License - see [LICENSE](LICENSE) file for
details.

## Authors

See the list of [contributors](https://github.com/lifeomic/cli/contributors) who participate in this project.
See the list of [contributors](https://github.com/lifeomic/cli/contributors) who
participate in this project.
41 changes: 37 additions & 4 deletions lifeomic_logging/logger.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
from logging import Formatter, Filter, StreamHandler, getLogger, INFO, Logger
from json import dumps
from contextlib import contextmanager
from typing import Generator, Optional

thread_local_storage = threading.local()

Expand Down Expand Up @@ -36,14 +37,46 @@
)


class JsonLogger(Logger):
"""
A logger that logs in JSON format. Supports creating child loggers with
expanded context, similar to the NodeJS Bunyan logger.
"""

def __init__(
self,
name: str,
context: Optional[dict] = None,
level: int = INFO,
):
super().__init__(name, level)
self.context = context if context is not None else {}
handler = StreamHandler()
handler.setFormatter(_JSONFormatter())
self.addHandler(handler)

def child(self, additional_context: dict):
child_context = {**self.context, **additional_context}
child_logger = self.__class__(
name=self.name, level=self.level, context=child_context
)
return child_logger

def _log(self, level, msg, args, exc_info=None, extra=None, stack_info=False):
if extra is None:
extra = {}
extra.update(self.context)
super()._log(level, msg, args, exc_info, extra, stack_info)


@contextmanager
def scoped_logger(
logname: str,
normal_context: dict = None,
error_context: dict = None,
normal_context: Optional[dict] = None,
error_context: Optional[dict] = None,
stream=None,
level: int = INFO,
) -> Logger:
) -> Generator[Logger, None, None]:
"""Creates a scopped logger
Parameters
Expand Down Expand Up @@ -84,7 +117,7 @@ def scoped_logger(
)


def get_request_context(lambda_context: dict) -> dict:
def get_request_context(lambda_context: dict) -> Optional[dict]:
"""Helper method to retrieve our most pertinent header information.
These are stored from the passed in lambda_context
object. Please see
Expand Down
2 changes: 1 addition & 1 deletion lifeomic_logging/version.py
Original file line number Diff line number Diff line change
@@ -1 +1 @@
__version__ = "0.3.2"
__version__ = "0.4.0"
Loading

0 comments on commit 08f9933

Please sign in to comment.