mh_structlog 0.0.45__tar.gz → 0.0.46__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: mh_structlog
3
- Version: 0.0.45
3
+ Version: 0.0.46
4
4
  Summary: Some Structlog configuration and wrappers to easily use structlog.
5
5
  Author: Mathieu Hinderyckx
6
6
  Author-email: Mathieu Hinderyckx <mathieu.hinderyckx@gmail.com>
@@ -8,7 +8,7 @@ authors = [
8
8
  { name = "Mathieu Hinderyckx", email = "mathieu.hinderyckx@gmail.com" },
9
9
  ]
10
10
  description = "Some Structlog configuration and wrappers to easily use structlog."
11
- version = "0.0.45"
11
+ version = "0.0.46"
12
12
  readme = "README.md"
13
13
  requires-python = ">=3.10"
14
14
  classifiers = [
@@ -1,18 +1,39 @@
1
+ import os
2
+
1
3
  import structlog
2
4
  from aws_lambda_powertools.utilities.typing import LambdaContext
3
5
 
4
6
 
7
+ is_cold_start = True
8
+
9
+
10
+ def _reset_cold_start_flag() -> None:
11
+ """Reset the cold start flag to True. This is primarily intended for testing purposes."""
12
+ global is_cold_start # noqa: PLW0603
13
+ is_cold_start = True
14
+
15
+
5
16
  def bind_lambda_context(lambda_context: LambdaContext) -> None:
6
17
  """Bind AWS Lambda context information to the structlog context variables, so log entries contain Lambda function metadata.
7
18
 
8
19
  Args:
9
20
  lambda_context (LambdaContext): The AWS Lambda context object.
10
21
  """
22
+ global is_cold_start # noqa: PLW0603
23
+
11
24
  if lambda_context:
12
25
  structlog.contextvars.clear_contextvars()
26
+
27
+ if os.getenv('AWS_LAMBDA_INITIALIZATION_TYPE', '') == "provisioned-concurrency":
28
+ is_cold_start = False
29
+
13
30
  structlog.contextvars.bind_contextvars(
14
31
  function_name=lambda_context.function_name,
15
32
  function_memory_size=lambda_context.memory_limit_in_mb,
16
33
  function_arn=lambda_context.invoked_function_arn,
17
34
  function_request_id=lambda_context.aws_request_id,
35
+ cold_start=is_cold_start,
18
36
  )
37
+
38
+ # After the first invocation of an environment, set cold_start to False for further invocations
39
+ is_cold_start = False
@@ -22,7 +22,7 @@ class StructlogLoggingConfigExceptionError(Exception):
22
22
 
23
23
 
24
24
  def setup( # noqa: PLR0912, PLR0915, C901
25
- log_format: Literal["console", "json", "gcp_json"] | None = None,
25
+ log_format: Literal["console", "json", "gcp_json", "aws_json"] | None = None,
26
26
  logging_configs: list[dict] | None = None,
27
27
  include_source_location: bool = False, # noqa: FBT001, FBT002
28
28
  global_filter_level: int | None = None,
@@ -64,7 +64,14 @@ def setup( # noqa: PLR0912, PLR0915, C901
64
64
  # Configure stdout formatter
65
65
  if log_format is None:
66
66
  log_format = "console" if sys.stdout.isatty() else "json"
67
- if log_format not in {"console", "json", "gcp_json"}:
67
+
68
+ # Determine a more specific log format based on environment if possible.
69
+ if log_format == "json":
70
+ if os.environ.get("GCP_PROJECT"):
71
+ log_format = "gcp_json"
72
+ elif os.environ.get("AWS_REGION"):
73
+ log_format = "aws_json"
74
+ if log_format not in {"console", "json", "gcp_json", "aws_json"}:
68
75
  raise StructlogLoggingConfigExceptionError("Unknown logging format requested.")
69
76
 
70
77
  SELECTED_LOG_FORMAT = log_format
@@ -90,7 +97,7 @@ def setup( # noqa: PLR0912, PLR0915, C901
90
97
 
91
98
  if log_format == "console":
92
99
  selected_formatter = "mh_structlog_colored"
93
- elif log_format in {"json", "gcp_json"}:
100
+ elif log_format in {"json", "gcp_json", "aws_json"}:
94
101
  shared_processors.extend(
95
102
  [structlog.processors.dict_tracebacks, processors.CapExceptionFrames(max_frames=2 * max_frames)]
96
103
  )
@@ -199,6 +206,7 @@ def setup( # noqa: PLR0912, PLR0915, C901
199
206
  processors.FieldRenamer(
200
207
  log_format == 'gcp_json', 'level', 'severity'
201
208
  ), # rename the level field for GCP
209
+ processors.FieldTransformer(log_format == 'aws_json', 'level', lambda v: v.upper()),
202
210
  processors.render_orjson,
203
211
  ],
204
212
  "foreign_pre_chain": shared_processors,
@@ -1,4 +1,5 @@
1
1
  import logging
2
+ from collections.abc import Callable
2
3
 
3
4
  import orjson
4
5
  import structlog
@@ -81,6 +82,20 @@ class FieldRenamer:
81
82
  return event_dict
82
83
 
83
84
 
85
+ class FieldTransformer:
86
+ """Transform a field in the event dict using a provided function."""
87
+
88
+ def __init__(self, enable: bool, field_name: str, transform_function: Callable): # noqa: D107
89
+ self.enable = enable
90
+ self.field_name = field_name
91
+ self.transform_function = transform_function
92
+
93
+ def __call__(self, logger: logging.Logger, name: str, event_dict: EventDict) -> EventDict: # noqa: D102,ARG001,ARG002
94
+ if self.enable and self.field_name in event_dict:
95
+ event_dict[self.field_name] = self.transform_function(event_dict[self.field_name])
96
+ return event_dict
97
+
98
+
84
99
  class CapExceptionFrames:
85
100
  """Limit the number of frames in the exception traceback.
86
101
 
File without changes