From 6496e81f5f2d34bbab96e0d4a196b47974865c94 Mon Sep 17 00:00:00 2001 From: "Difrango, Ronald" Date: Tue, 5 Oct 2021 13:47:15 -0400 Subject: [PATCH 1/5] Resolves #57 See: https://github.com/elastic/ecs-logging-python/issues/57 --- ecs_logging/_stdlib.py | 6 ++++++ tests/test_stdlib_formatter.py | 14 +++++++++++++- 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/ecs_logging/_stdlib.py b/ecs_logging/_stdlib.py index 9620ea6..12d1614 100644 --- a/ecs_logging/_stdlib.py +++ b/ecs_logging/_stdlib.py @@ -78,6 +78,7 @@ def __init__( style="%", validate=None, stack_trace_limit=None, + extra=None, exclude_fields=(), ): # type: (Any, Optional[str], Optional[str], str, Optional[bool], Optional[int], Sequence[str]) -> None @@ -129,6 +130,7 @@ def __init__( ): raise TypeError("'exclude_fields' must be a sequence of strings") + self._extra = extra self._exclude_fields = frozenset(exclude_fields) self._stack_trace_limit = stack_trace_limit @@ -218,6 +220,10 @@ def format_to_ecs(self, record): # since they can be defined as 'extras={"http": {"method": "GET"}}' extra_keys = set(available).difference(self._LOGRECORD_DICT) extras = flatten_dict({key: available[key] for key in extra_keys}) + # Merge in any global extra's + if self._extra is not None: + for field, value in self._extra.items(): + merge_dicts(de_dot(field, value), extras) # Pop all Elastic APM extras and add them # to standard tracing ECS fields. diff --git a/tests/test_stdlib_formatter.py b/tests/test_stdlib_formatter.py index af320ea..440e790 100644 --- a/tests/test_stdlib_formatter.py +++ b/tests/test_stdlib_formatter.py @@ -26,7 +26,6 @@ import ecs_logging from .compat import StringIO - requires_py3 = pytest.mark.skipif( sys.version_info[0] < 3, reason="Test requires Python 3.x+" ) @@ -63,6 +62,19 @@ def test_record_formatted(spec_validator): ) +def test_extra_global_is_merged(spec_validator): + formatter = ecs_logging.StdlibFormatter( + exclude_fields=["process"], extra={"environment": "dev"} + ) + + assert spec_validator(formatter.format(make_record())) == ( + '{"@timestamp":"2020-03-20T14:12:46.123Z","log.level":"debug","message":"1: hello","ecs":{"version":"1.6.0"},' + '"environment":"dev",' + '"log":{"logger":"logger-name","origin":{"file":{"line":10,"name":"file.py"},"function":"test_function"},' + '"original":"1: hello"}}' + ) + + def test_can_be_overridden(spec_validator): class CustomFormatter(ecs_logging.StdlibFormatter): def format_to_ecs(self, record): From fa86fd6cd4cf6bdde98f0a457e0124e3d3fde48e Mon Sep 17 00:00:00 2001 From: rdifrango Date: Mon, 11 Oct 2021 15:50:05 -0400 Subject: [PATCH 2/5] Update _stdlib.py Updated the type hints. --- ecs_logging/_stdlib.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/ecs_logging/_stdlib.py b/ecs_logging/_stdlib.py index 12d1614..c634d8b 100644 --- a/ecs_logging/_stdlib.py +++ b/ecs_logging/_stdlib.py @@ -81,7 +81,7 @@ def __init__( extra=None, exclude_fields=(), ): - # type: (Any, Optional[str], Optional[str], str, Optional[bool], Optional[int], Sequence[str]) -> None + # type: (Any, Optional[str], Optional[str], str, Optional[bool], Optional[int], Dict[str], Sequence[str]) -> None """Initialize the ECS formatter. :param int stack_trace_limit: @@ -90,6 +90,8 @@ def __init__( Setting this to zero will suppress stack traces. This setting doesn't affect ``LogRecord.stack_info`` because this attribute is typically already pre-formatted. + :param Dict[str] extra: + Specifies the collection of meta-data fields to add to all records. :param Sequence[str] exclude_fields: Specifies any fields that should be suppressed from the resulting fields, expressed with dot notation:: From 7f0753a14aea3aa0a7516747773e6251c1a56d59 Mon Sep 17 00:00:00 2001 From: Colton Myers Date: Tue, 12 Oct 2021 11:09:05 -0600 Subject: [PATCH 3/5] Fix lint (mypy and line length) --- ecs_logging/_stdlib.py | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/ecs_logging/_stdlib.py b/ecs_logging/_stdlib.py index c634d8b..7764082 100644 --- a/ecs_logging/_stdlib.py +++ b/ecs_logging/_stdlib.py @@ -72,16 +72,16 @@ class StdlibFormatter(logging.Formatter): converter = time.gmtime def __init__( - self, - fmt=None, - datefmt=None, - style="%", - validate=None, - stack_trace_limit=None, - extra=None, - exclude_fields=(), + self, # type: Any + fmt=None, # type: Optional[str] + datefmt=None, # type: Optional[str] + style="%", # type: str + validate=None, # type: Optional[bool] + stack_trace_limit=None, # type: Optional[int] + extra=None, # type: Optional[Dict[Any, Any]] + exclude_fields=(), # type: Sequence[str] ): - # type: (Any, Optional[str], Optional[str], str, Optional[bool], Optional[int], Dict[str], Sequence[str]) -> None + # type: (...) -> None """Initialize the ECS formatter. :param int stack_trace_limit: From 69e518fd3a98a88efc9d1cf702e6d662cc33fc4e Mon Sep 17 00:00:00 2001 From: rdifrango Date: Wed, 27 Oct 2021 13:30:08 -0400 Subject: [PATCH 4/5] Update _stdlib.py --- ecs_logging/_stdlib.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ecs_logging/_stdlib.py b/ecs_logging/_stdlib.py index d574613..4ac0d5b 100644 --- a/ecs_logging/_stdlib.py +++ b/ecs_logging/_stdlib.py @@ -78,7 +78,7 @@ def __init__( style="%", # type: str validate=None, # type: Optional[bool] stack_trace_limit=None, # type: Optional[int] - extra=None, # type: Optional[Dict[Any, Any]] + extra=None, # type: Optional[Dict[str, Any]] exclude_fields=(), # type: Sequence[str] ): # type: (...) -> None From 1120ec0dcd95fd544b2f28928115bd5ec524a091 Mon Sep 17 00:00:00 2001 From: rdifrango Date: Wed, 27 Oct 2021 13:31:07 -0400 Subject: [PATCH 5/5] Update _stdlib.py --- ecs_logging/_stdlib.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ecs_logging/_stdlib.py b/ecs_logging/_stdlib.py index 4ac0d5b..76e03ed 100644 --- a/ecs_logging/_stdlib.py +++ b/ecs_logging/_stdlib.py @@ -90,7 +90,7 @@ def __init__( Setting this to zero will suppress stack traces. This setting doesn't affect ``LogRecord.stack_info`` because this attribute is typically already pre-formatted. - :param Dict[str] extra: + :param Optional[Dict[str, Any]] extra: Specifies the collection of meta-data fields to add to all records. :param Sequence[str] exclude_fields: Specifies any fields that should be suppressed from the resulting