Skip to content

Commit 5ca395a

Browse files
Changing documentation and method names
1 parent 3e35409 commit 5ca395a

13 files changed

+145
-105
lines changed

Diff for: aws_lambda_powertools/logging/formatter.py

+28-20
Original file line numberDiff line numberDiff line change
@@ -51,27 +51,29 @@ class BasePowertoolsFormatter(logging.Formatter, metaclass=ABCMeta):
5151
def append_keys(self, **additional_keys) -> None:
5252
raise NotImplementedError()
5353

54-
def append_thread_local_keys(self, **additional_keys) -> None:
55-
raise NotImplementedError()
56-
5754
def get_current_keys(self) -> dict[str, Any]:
5855
return {}
5956

60-
def get_current_thread_keys(self) -> dict[str, Any]:
61-
return {}
62-
6357
def remove_keys(self, keys: Iterable[str]) -> None:
6458
raise NotImplementedError()
6559

66-
def remove_thread_local_keys(self, keys: Iterable[str]) -> None:
67-
raise NotImplementedError()
68-
6960
@abstractmethod
7061
def clear_state(self) -> None:
7162
"""Removes any previously added logging keys"""
7263
raise NotImplementedError()
7364

74-
def clear_thread_local_keys(self) -> None:
65+
# These specific thread-safe methods are necessary to manage shared context in concurrent environments.
66+
# They prevent race conditions and ensure data consistency across multiple threads.
67+
def thread_safe_append_keys(self, **additional_keys) -> None:
68+
raise NotImplementedError()
69+
70+
def thread_safe_get_current_keys(self) -> dict[str, Any]:
71+
return {}
72+
73+
def thread_safe_remove_keys(self, keys: Iterable[str]) -> None:
74+
raise NotImplementedError()
75+
76+
def thread_safe_clear_keys(self) -> None:
7577
"""Removes any previously added logging keys in a specific thread"""
7678
raise NotImplementedError()
7779

@@ -250,27 +252,33 @@ def formatTime(self, record: logging.LogRecord, datefmt: str | None = None) -> s
250252
def append_keys(self, **additional_keys) -> None:
251253
self.log_format.update(additional_keys)
252254

253-
def append_thread_local_keys(self, **additional_keys) -> None:
254-
set_context_keys(**additional_keys)
255-
256255
def get_current_keys(self) -> dict[str, Any]:
257256
return self.log_format
258257

259-
def get_current_thread_keys(self) -> dict[str, Any]:
260-
return _get_context().get()
261-
262258
def remove_keys(self, keys: Iterable[str]) -> None:
263259
for key in keys:
264260
self.log_format.pop(key, None)
265261

266-
def remove_thread_local_keys(self, keys: Iterable[str]) -> None:
267-
remove_context_keys(keys)
268-
269262
def clear_state(self) -> None:
270263
self.log_format = dict.fromkeys(self.log_record_order)
271264
self.log_format.update(**self.keys_combined)
272265

273-
def clear_thread_local_keys(self) -> None:
266+
# These specific thread-safe methods are necessary to manage shared context in concurrent environments.
267+
# They prevent race conditions and ensure data consistency across multiple threads.
268+
def thread_safe_append_keys(self, **additional_keys) -> None:
269+
# Append additional key-value pairs to the context safely in a thread-safe manner.
270+
set_context_keys(**additional_keys)
271+
272+
def thread_safe_get_current_keys(self) -> dict[str, Any]:
273+
# Retrieve the current context keys safely in a thread-safe manner.
274+
return _get_context().get()
275+
276+
def thread_safe_remove_keys(self, keys: Iterable[str]) -> None:
277+
# Remove specified keys from the context safely in a thread-safe manner.
278+
remove_context_keys(keys)
279+
280+
def thread_safe_clear_keys(self) -> None:
281+
# Clear all keys from the context safely in a thread-safe manner.
274282
clear_context_keys()
275283

276284
@staticmethod

Diff for: aws_lambda_powertools/logging/logger.py

+17-11
Original file line numberDiff line numberDiff line change
@@ -583,23 +583,29 @@ def debug(
583583
def append_keys(self, **additional_keys: object) -> None:
584584
self.registered_formatter.append_keys(**additional_keys)
585585

586-
def append_thread_local_keys(self, **additional_keys: object) -> None:
587-
self.registered_formatter.append_thread_local_keys(**additional_keys)
588-
589586
def get_current_keys(self) -> dict[str, Any]:
590587
return self.registered_formatter.get_current_keys()
591588

592-
def get_current_thread_keys(self) -> dict[str, Any]:
593-
return self.registered_formatter.get_current_thread_keys()
594-
595589
def remove_keys(self, keys: Iterable[str]) -> None:
596590
self.registered_formatter.remove_keys(keys)
597591

598-
def remove_thread_local_keys(self, keys: Iterable[str]) -> None:
599-
self.registered_formatter.remove_thread_local_keys(keys)
592+
# These specific thread-safe methods are necessary to manage shared context in concurrent environments.
593+
# They prevent race conditions and ensure data consistency across multiple threads.
594+
def thread_safe_append_keys(self, **additional_keys: object) -> None:
595+
# Append additional key-value pairs to the context safely in a thread-safe manner.
596+
self.registered_formatter.thread_safe_append_keys(**additional_keys)
597+
598+
def thread_safe_get_current_keys(self) -> dict[str, Any]:
599+
# Retrieve the current context keys safely in a thread-safe manner.
600+
return self.registered_formatter.thread_safe_get_current_keys()
601+
602+
def thread_safe_remove_keys(self, keys: Iterable[str]) -> None:
603+
# Remove specified keys from the context safely in a thread-safe manner.
604+
self.registered_formatter.thread_safe_remove_keys(keys)
600605

601-
def clear_thread_local_keys(self) -> None:
602-
self.registered_formatter.clear_thread_local_keys()
606+
def thread_safe_clear_keys(self) -> None:
607+
# Clear all keys from the context safely in a thread-safe manner.
608+
self.registered_formatter.thread_safe_clear_keys()
603609

604610
def structure_logs(self, append: bool = False, formatter_options: dict | None = None, **keys) -> None:
605611
"""Sets logging formatting to JSON.
@@ -645,7 +651,7 @@ def structure_logs(self, append: bool = False, formatter_options: dict | None =
645651

646652
# Mode 3
647653
self.registered_formatter.clear_state()
648-
self.registered_formatter.clear_thread_local_keys()
654+
self.registered_formatter.thread_safe_clear_keys()
649655
self.registered_formatter.append_keys(**log_keys)
650656

651657
def set_correlation_id(self, value: str | None) -> None:

Diff for: docs/core/event_handler/api_gateway.md

+2-1
Original file line numberDiff line numberDiff line change
@@ -128,11 +128,12 @@ Here's an example on how we can handle the `/todos` path.
128128

129129
When using Amazon API Gateway HTTP API to front your Lambda functions, you can use `APIGatewayHttpResolver`.
130130

131+
<!-- markdownlint-disable MD013 -->
131132
???+ note
132133
Using HTTP API v1 payload? Use `APIGatewayRestResolver` instead. `APIGatewayHttpResolver` defaults to v2 payload.
133134

134-
<!-- markdownlint-disable-next-line MD013 -->
135135
If you're using Terraform to deploy a HTTP API, note that it defaults the [payload_format_version](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/apigatewayv2_integration#payload_format_version){target="_blank" rel="nofollow"} value to 1.0 if not specified.
136+
<!-- markdownlint-enable MD013 -->
136137

137138
```python hl_lines="5 11" title="Using HTTP API resolver"
138139
--8<-- "examples/event_handler_rest/src/getting_started_http_api_resolver.py"

Diff for: docs/core/logger.md

+66-55
Original file line numberDiff line numberDiff line change
@@ -160,13 +160,13 @@ To ease routine tasks like extracting correlation ID from popular event sources,
160160
You can append additional keys using either mechanism:
161161

162162
* New keys persist across all future log messages via `append_keys` method
163-
* New keys persist across all future logs in a specific thread via `append_thread_local_keys` method
164163
* Add additional keys on a per log message basis as a keyword=value, or via `extra` parameter
164+
* New keys persist across all future logs in a specific thread via `thread_safe_append_keys` method. Check [Working with thread-safe keys](#working-with-thread-safe-keys) section.
165165

166166
#### append_keys method
167167

168168
???+ warning
169-
`append_keys` is not thread-safe, use `append_thread_local_keys` instead
169+
`append_keys` is not thread-safe, use [thread_safe_append_keys](#appending-thread-safe-additional-keys) instead
170170

171171
You can append your own keys to your existing Logger via `append_keys(**additional_key_values)` method.
172172

@@ -187,22 +187,6 @@ You can append your own keys to your existing Logger via `append_keys(**addition
187187

188188
This example will add `order_id` if its value is not empty, and in subsequent invocations where `order_id` might not be present it'll remove it from the Logger.
189189

190-
#### append_thread_local_keys method
191-
192-
You can append your own thread-local keys in your existing Logger via the `append_thread_local_keys` method
193-
194-
=== "append_thread_local_keys.py"
195-
196-
```python hl_lines="11"
197-
--8<-- "examples/logger/src/append_thread_local_keys.py"
198-
```
199-
200-
=== "append_thread_local_keys_output.json"
201-
202-
```json hl_lines="8 9 17 18"
203-
--8<-- "examples/logger/src/append_thread_local_keys_output.json"
204-
```
205-
206190
#### ephemeral metadata
207191

208192
You can pass an arbitrary number of keyword arguments (kwargs) to all log level's methods, e.g. `logger.info, logger.warning`.
@@ -248,11 +232,10 @@ It accepts any dictionary, and all keyword arguments will be added as part of th
248232
You can remove additional keys using either mechanism:
249233

250234
* Remove new keys across all future log messages via `remove_keys` method
251-
* Remove new keys across all future logs in a specific thread via `remove_thread_local_keys` method
252-
* Remove **all** new keys across all future logs in a specific thread via `clear_thread_local_keys` method
235+
* Remove keys persist across all future logs in a specific thread via `thread_safe_remove_keys` method. Check [Working with thread-safe keys](#working-with-thread-safe-keys) section.
253236

254237
???+ danger
255-
Keys added by `append_keys` can only be removed by `remove_keys` and thread-local keys added by `append_thread_local_key` can only be removed by `remove_thread_local_keys` or `clear_thread_local_keys`. Thread-local and normal logger keys are distinct values and can't be manipulated interchangably.
238+
Keys added by `append_keys` can only be removed by `remove_keys` and thread-local keys added by `thread_safe_append_keys` can only be removed by `thread_safe_remove_keys` or `thread_safe_clear_keys`. Thread-local and normal logger keys are distinct values and can't be manipulated interchangeably.
256239

257240
#### remove_keys method
258241

@@ -270,40 +253,6 @@ You can remove any additional key from Logger state using `remove_keys`.
270253
--8<-- "examples/logger/src/remove_keys_output.json"
271254
```
272255

273-
#### remove_thread_local_keys method
274-
275-
You can remove any additional thread-local keys from Logger using either `remove_thread_local_keys` or `clear_thread_local_keys`.
276-
277-
Use the `remove_thread_local_keys` method to remove a list of thread-local keys that were previously added using the `append_thread_local_keys` method.
278-
279-
=== "remove_thread_local_keys.py"
280-
281-
```python hl_lines="13"
282-
--8<-- "examples/logger/src/remove_thread_local_keys.py"
283-
```
284-
285-
=== "remove_thread_local_keys_output.json"
286-
287-
```json hl_lines="8 9 17 18 26 34"
288-
--8<-- "examples/logger/src/remove_thread_local_keys_output.json"
289-
```
290-
291-
#### clear_thread_local_keys method
292-
293-
Use the `clear_thread_local_keys` method to remove all thread-local keys that were previously added using the `append_thread_local_keys` method.
294-
295-
=== "clear_thread_local_keys.py"
296-
297-
```python hl_lines="13"
298-
--8<-- "examples/logger/src/clear_thread_local_keys.py"
299-
```
300-
301-
=== "clear_thread_local_keys_output.json"
302-
303-
```json hl_lines="8 9 17 18"
304-
--8<-- "examples/logger/src/clear_thread_local_keys_output.json"
305-
```
306-
307256
#### Clearing all state
308257

309258
Logger is commonly initialized in the global scope. Due to [Lambda Execution Context reuse](https://docs.aws.amazon.com/lambda/latest/dg/runtimes-context.html){target="_blank"}, this means that custom keys can be persisted across invocations. If you want all custom keys to be deleted, you can use `clear_state=True` param in `inject_lambda_context` decorator.
@@ -538,6 +487,68 @@ You can use any of the following built-in JMESPath expressions as part of [injec
538487
| **APPLICATION_LOAD_BALANCER** | `'headers."x-amzn-trace-id"'` | ALB X-Ray Trace ID |
539488
| **EVENT_BRIDGE** | `"id"` | EventBridge Event ID |
540489

490+
### Working with thread-safe keys
491+
492+
#### Appending thread-safe additional keys
493+
494+
You can append your own thread-local keys in your existing Logger via the `thread_safe_append_keys` method
495+
496+
=== "thread_safe_append_keys.py"
497+
498+
```python hl_lines="11"
499+
--8<-- "examples/logger/src/thread_safe_append_keys.py"
500+
```
501+
502+
=== "thread_safe_append_keys_output.json"
503+
504+
```json hl_lines="8 9 17 18"
505+
--8<-- "examples/logger/src/thread_safe_append_keys_output.json"
506+
```
507+
508+
#### Removing thread-safe additional keys
509+
510+
You can remove any additional thread-local keys from Logger using either `thread_safe_remove_keys` or `thread_safe_clear_keys`.
511+
512+
Use the `thread_safe_remove_keys` method to remove a list of thread-local keys that were previously added using the `thread_safe_append_keys` method.
513+
514+
=== "thread_safe_remove_keys.py"
515+
516+
```python hl_lines="13"
517+
--8<-- "examples/logger/src/thread_safe_remove_keys.py"
518+
```
519+
520+
=== "thread_safe_remove_keys_output.json"
521+
522+
```json hl_lines="8 9 17 18 26 34"
523+
--8<-- "examples/logger/src/thread_safe_remove_keys_output.json"
524+
```
525+
526+
#### Clearing thread-safe additional keys
527+
528+
Use the `thread_safe_clear_keys` method to remove all thread-local keys that were previously added using the `thread_safe_append_keys` method.
529+
530+
=== "thread_safe_clear_keys.py"
531+
532+
```python hl_lines="13"
533+
--8<-- "examples/logger/src/thread_safe_clear_keys.py"
534+
```
535+
536+
=== "thread_safe_clear_keys_output.json"
537+
538+
```json hl_lines="8 9 17 18"
539+
--8<-- "examples/logger/src/thread_safe_clear_keys_output.json"
540+
```
541+
542+
#### Accessing thread-safe currently keys
543+
544+
You can view all currently thread-local keys from the Logger state using the `thread_safe_get_current_keys()` method. This method is useful when you need to avoid overwriting keys that are already configured.
545+
546+
=== "thread_safe_get_current_keys.py"
547+
548+
```python hl_lines="13"
549+
--8<-- "examples/logger/src/thread_safe_get_current_keys.py"
550+
```
551+
541552
### Reusing Logger across your code
542553

543554
Similar to [Tracer](./tracer.md#reusing-tracer-across-your-code){target="_blank"}, a new instance that uses the same `service` name will reuse a previous Logger instance.

Diff for: examples/logger/src/append_thread_local_keys.py renamed to examples/logger/src/thread_safe_append_keys.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88

99

1010
def threaded_func(order_id: str):
11-
logger.append_thread_local_keys(order_id=order_id, thread_id=threading.get_ident())
11+
logger.thread_safe_append_keys(order_id=order_id, thread_id=threading.get_ident())
1212
logger.info("Collecting payment")
1313

1414

Diff for: examples/logger/src/clear_thread_local_keys.py renamed to examples/logger/src/thread_safe_clear_keys.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,9 @@
88

99

1010
def threaded_func(order_id: str):
11-
logger.append_thread_local_keys(order_id=order_id, thread_id=threading.get_ident())
11+
logger.thread_safe_append_keys(order_id=order_id, thread_id=threading.get_ident())
1212
logger.info("Collecting payment")
13-
logger.clear_thread_local_keys()
13+
logger.thread_safe_clear_keys()
1414
logger.info("Exiting thread")
1515

1616

Diff for: examples/logger/src/thread_safe_get_current_keys.py

+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
from aws_lambda_powertools import Logger
2+
from aws_lambda_powertools.utilities.typing import LambdaContext
3+
4+
logger = Logger()
5+
6+
7+
@logger.inject_lambda_context
8+
def lambda_handler(event: dict, context: LambdaContext) -> str:
9+
logger.info("Collecting payment")
10+
11+
if "order" not in logger.thread_safe_get_current_keys():
12+
logger.thread_safe_append_keys(order=event.get("order"))
13+
14+
return "hello world"

Diff for: examples/logger/src/remove_thread_local_keys.py renamed to examples/logger/src/thread_safe_remove_keys.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,9 @@
88

99

1010
def threaded_func(order_id: str):
11-
logger.append_thread_local_keys(order_id=order_id, thread_id=threading.get_ident())
11+
logger.thread_safe_append_keys(order_id=order_id, thread_id=threading.get_ident())
1212
logger.info("Collecting payment")
13-
logger.remove_thread_local_keys(["order_id"])
13+
logger.thread_safe_remove_keys(["order_id"])
1414
logger.info("Exiting thread")
1515

1616

Diff for: tests/functional/event_handler/_pydantic/conftest.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@ def pydanticv2_only():
9797
def openapi30_schema():
9898
from urllib.request import urlopen
9999

100-
f = urlopen("https://raw.githubusercontent.com/OAI/OpenAPI-Specification/main/schemas/v3.0/schema.json")
100+
f = urlopen("https://spec.openapis.org/oas/3.0/schema/2021-09-28")
101101
data = json.loads(f.read().decode("utf-8"))
102102
return fastjsonschema.compile(
103103
data,
@@ -109,7 +109,7 @@ def openapi30_schema():
109109
def openapi31_schema():
110110
from urllib.request import urlopen
111111

112-
f = urlopen("https://raw.githubusercontent.com/OAI/OpenAPI-Specification/main/schemas/v3.1/schema.json")
112+
f = urlopen("https://spec.openapis.org/oas/3.1/schema/2022-10-07")
113113
data = json.loads(f.read().decode("utf-8"))
114114
return fastjsonschema.compile(
115115
data,

0 commit comments

Comments
 (0)