diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 8a4ff5b..ffab351 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,16 +1,16 @@ repos: - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v4.0.1 + rev: v5.0.0 hooks: - id: check-case-conflict - id: check-executables-have-shebangs - id: check-merge-conflict - repo: https://github.com/elastic/apm-pipeline-library - rev: current + rev: v1.19.13 hooks: - id: check-bash-syntax - repo: https://github.com/pre-commit/mirrors-mypy - rev: v0.910 + rev: v1.15.0 hooks: - id: mypy args: @@ -21,12 +21,12 @@ repos: --implicit-reexport, ] - repo: https://github.com/psf/black - rev: 22.12.0 + rev: 25.1.0 hooks: - id: black language_version: python3 - repo: https://github.com/pycqa/flake8 - rev: 3.9.2 + rev: 7.1.1 hooks: - id: flake8 exclude: tests|conftest.py|setup.py diff --git a/ecs_logging/_stdlib.py b/ecs_logging/_stdlib.py index 7839a7d..f53fc64 100644 --- a/ecs_logging/_stdlib.py +++ b/ecs_logging/_stdlib.py @@ -30,12 +30,7 @@ merge_dicts, ) -from typing import Any, Callable, Dict, Optional, Sequence, Union - -try: - from typing import Literal # type: ignore -except ImportError: - from typing_extensions import Literal # type: ignore +from typing import Any, Callable, Dict, Optional, Sequence, Union, Literal # Load the attributes of a LogRecord so if some are @@ -164,21 +159,25 @@ def format(self, record: logging.LogRecord) -> str: result = self.format_to_ecs(record) return json_dumps(result) - def format_to_ecs(self, record: logging.LogRecord) -> Dict[str, Any]: - """Function that can be overridden to add additional fields to - (or remove fields from) the JSON before being dumped into a string. + @property + @lru_cache + def extractors(self) -> Dict[str, Callable[[logging.LogRecord], Any]]: + """Property that can be overridden to add additional field + extractors to (or remove fields from) the JSON before being + dumped into a string. .. code-block: python class MyFormatter(StdlibFormatter): - def format_to_ecs(self, record): - result = super().format_to_ecs(record) - del result["log"]["original"] # remove unwanted field(s) - result["my_field"] = "my_value" # add custom field - return result + @property + @lru_cache + def extractors(self): + extractors = super().extractors + del extractors["log.original"] # remove unwanted field(s) + extractors["my_field"] = self._my_extractor # add custom field + return extractors """ - - extractors: Dict[str, Callable[[logging.LogRecord], Any]] = { + return { "@timestamp": self._record_timestamp, "ecs.version": lambda _: ECS_VERSION, "log.level": lambda r: (r.levelname.lower() if r.levelname else None), @@ -196,11 +195,24 @@ def format_to_ecs(self, record): "error.stack_trace": self._record_error_stack_trace, } + def format_to_ecs(self, record: logging.LogRecord) -> Dict[str, Any]: + """Function that can be overridden to add additional fields to + (or remove fields from) the JSON before being dumped into a string. + + .. code-block: python + + class MyFormatter(StdlibFormatter): + def format_to_ecs(self, record): + result = super().format_to_ecs(record) + del result["log"]["original"] # remove unwanted field(s) + result["my_field"] = "my_value" # add custom field + return result + """ result: Dict[str, Any] = {} - for field in set(extractors.keys()).difference(self._exclude_fields): + for field in set(self.extractors.keys()).difference(self._exclude_fields): if self._is_field_excluded(field): continue - value = extractors[field](record) + value = self.extractors[field](record) if value is not None: # special case ecs.version that should not be de-dotted if field == "ecs.version":