|
| 1 | +--- |
| 2 | +title: Logger |
| 3 | +description: Core utility |
| 4 | +--- |
| 5 | + |
| 6 | +import Note from "../../src/components/Note" |
| 7 | + |
| 8 | +Logger provides an opinionated logger with output structured as JSON. |
| 9 | + |
| 10 | +**Key features** |
| 11 | + |
| 12 | +* Capture key fields from Lambda context, cold start and structures logging output as JSON |
| 13 | +* Log Lambda event when instructed (disabled by default) |
| 14 | + - Enable via `POWERTOOLS_LOGGER_LOG_EVENT="true"` or explicitly via decorator param |
| 15 | +* Log sampling enables DEBUG log level for a percentage of requests (disabled by default) |
| 16 | + - Enable via `POWERTOOLS_LOGGER_SAMPLE_RATE=0.1`, ranges from 0 to 1, where 0.1 is 10% and 1 is 100% |
| 17 | +* Append additional keys to structured log at any point in time |
| 18 | + |
| 19 | +## Initialization |
| 20 | + |
| 21 | +Set `LOG_LEVEL` env var as a start - Here is an example using AWS Serverless Application Model (SAM) |
| 22 | + |
| 23 | +```yaml:title=template.yaml |
| 24 | +Resources: |
| 25 | + HelloWorldFunction: |
| 26 | + Type: AWS::Serverless::Function |
| 27 | + Properties: |
| 28 | + ... |
| 29 | + Runtime: python3.8 |
| 30 | + Environment: |
| 31 | + Variables: |
| 32 | + LOG_LEVEL: INFO # highlight-line |
| 33 | +``` |
| 34 | + |
| 35 | +By default, Logger uses **INFO** log level. You can either change log level via `level` param or via env var. |
| 36 | + |
| 37 | +You can also explicitly set a service name via `service` param or via `POWERTOOLS_SERVICE_NAME` env var. This sets **service** key that will be present across all log statements. |
| 38 | + |
| 39 | +```python:title=app.py |
| 40 | +from aws_lambda_powertools.logging import Logger |
| 41 | +# POWERTOOLS_SERVICE_NAME defined |
| 42 | +logger = Logger() # highlight-line |
| 43 | + |
| 44 | +# Explicit definition |
| 45 | +Logger(service="payment", level="INFO") |
| 46 | +``` |
| 47 | + |
| 48 | +## Standard structured keys |
| 49 | + |
| 50 | +Your Logger will always include the following keys to your structured logging: |
| 51 | + |
| 52 | +Key | Type | Example | Description |
| 53 | +------------------------------------------------- | ------------------------------------------------- | --------------------------------------------------------------------------------- | ------------------------------------------------- |
| 54 | +**timestamp** | str | "2020-05-24 18:17:33,774" | Timestamp of actual log statement |
| 55 | +**level** | str | "INFO" | Logging level |
| 56 | +**location** | str | "collect.handler:1" | Source code location where statement was executed |
| 57 | +**service** | str | "payment" | Service name defined. "service_undefined" will be used if unknown |
| 58 | +**sampling_rate** | int | 0.1 | Debug logging sampling rate in percentage e.g. 1% in this case |
| 59 | +**message** | any | "Collecting payment" | Log statement value. Unserializable JSON values will be casted to string |
| 60 | + |
| 61 | +## Capturing context Lambda info |
| 62 | + |
| 63 | +You can enrich your structured logs with key Lambda context information via `inject_lambda_context`. |
| 64 | + |
| 65 | +```python:title=collect.py |
| 66 | +from aws_lambda_powertools.logging import Logger |
| 67 | + |
| 68 | +logger = Logger() |
| 69 | + |
| 70 | +@logger.inject_lambda_context |
| 71 | +def handler(event, context) |
| 72 | + logger.info("Collecting payment") |
| 73 | + ... |
| 74 | + # You can log entire objects too |
| 75 | + logger.info({ |
| 76 | + "operation": "collect_payment", |
| 77 | + "charge_id": event['charge_id'] |
| 78 | + }) |
| 79 | + ... |
| 80 | +``` |
| 81 | + |
| 82 | +You can also explicitly log any incoming event using `log_event` param or via `POWERTOOLS_LOGGER_LOG_EVENT` env var. |
| 83 | + |
| 84 | +<Note type="warning"> |
| 85 | + This is disabled by default to prevent sensitive info being logged. |
| 86 | +</Note><br/> |
| 87 | + |
| 88 | +```python:title=log_handler_event.py |
| 89 | +from aws_lambda_powertools.logging import Logger |
| 90 | + |
| 91 | +logger = Logger() |
| 92 | + |
| 93 | +@logger.inject_lambda_context(log_event=True) # highlight-start |
| 94 | +def handler(event, context) |
| 95 | + ... |
| 96 | +``` |
| 97 | + |
| 98 | +When used, this will include the following keys: |
| 99 | + |
| 100 | +Key | Type | Example |
| 101 | +------------------------------------------------- | ------------------------------------------------- | --------------------------------------------------------------------------------- |
| 102 | +**cold_start**| bool | false |
| 103 | +**function_name**| str | "example-powertools-HelloWorldFunction-1P1Z6B39FLU73" |
| 104 | +**function_memory_size**| int | 128 |
| 105 | +**function_arn**| str | "arn:aws:lambda:eu-west-1:012345678910:function:example-powertools-HelloWorldFunction-1P1Z6B39FLU73" |
| 106 | +**function_request_id**| str | "899856cb-83d1-40d7-8611-9e78f15f32f4" |
| 107 | + |
| 108 | +<details> |
| 109 | +<summary><strong>Exerpt output in CloudWatch Logs</strong></summary> |
| 110 | + |
| 111 | +```json:title=cloudwatch_logs.json |
| 112 | +{ |
| 113 | + "timestamp":"2020-05-24 18:17:33,774", |
| 114 | + "level":"INFO", |
| 115 | + "location":"collect.handler:1", |
| 116 | + "service":"payment", |
| 117 | +// highlight-start |
| 118 | + "lambda_function_name":"test", |
| 119 | + "lambda_function_memory_size": 128, |
| 120 | + "lambda_function_arn":"arn:aws:lambda:eu-west-1:12345678910:function:test", |
| 121 | + "lambda_request_id":"52fdfc07-2182-154f-163f-5f0f9a621d72", |
| 122 | + "cold_start": true, |
| 123 | +// highlight-end |
| 124 | + "sampling_rate": 0.0, |
| 125 | + "message": "Collecting payment" |
| 126 | +} |
| 127 | + |
| 128 | +{ |
| 129 | + "timestamp":"2020-05-24 18:17:33,774", |
| 130 | + "level":"INFO", |
| 131 | + "location":"collect.handler:15", |
| 132 | + "service":"payment", |
| 133 | + "lambda_function_name":"test", |
| 134 | + "lambda_function_memory_size": 128, |
| 135 | + "lambda_function_arn":"arn:aws:lambda:eu-west-1:12345678910:function:test", |
| 136 | + "lambda_request_id":"52fdfc07-2182-154f-163f-5f0f9a621d72", |
| 137 | + "cold_start": true, |
| 138 | + "sampling_rate": 0.0, |
| 139 | +// highlight-start |
| 140 | + "message":{ |
| 141 | + "operation":"collect_payment", |
| 142 | + "charge_id": "ch_AZFlk2345C0" |
| 143 | + } |
| 144 | +// highlight-end |
| 145 | +} |
| 146 | +``` |
| 147 | +</details> |
| 148 | + |
| 149 | +## Appending additional keys |
| 150 | + |
| 151 | +You can append your own keys to your existing Logger via `structure_logs` with **append** param. |
| 152 | + |
| 153 | +```python:title=collect.py |
| 154 | +from aws_lambda_powertools.logging import Logger |
| 155 | + |
| 156 | +logger = Logger() |
| 157 | + |
| 158 | +def handler(event, context) |
| 159 | + if "order_id" in event: |
| 160 | + logger.structure_logs(append=True, order_id=event["order_id"]) # highlight-line |
| 161 | + logger.info("Collecting payment") |
| 162 | + ... |
| 163 | +``` |
| 164 | + |
| 165 | +<details> |
| 166 | +<summary><strong>Exerpt output in CloudWatch Logs</strong></summary> |
| 167 | + |
| 168 | +```json:title=cloudwatch_logs.jsonn |
| 169 | +{ |
| 170 | + "timestamp": "2020-05-24 18:17:33,774", |
| 171 | + "level": "INFO", |
| 172 | + "location": "collect.handler:1", |
| 173 | + "service": "payment", |
| 174 | + "lambda_function_name": "test", |
| 175 | + "lambda_function_memory_size": 128, |
| 176 | + "lambda_function_arn": "arn:aws:lambda:eu-west-1:12345678910:function:test", |
| 177 | + "lambda_request_id": "52fdfc07-2182-154f-163f-5f0f9a621d72", |
| 178 | + "cold_start": true, |
| 179 | + "sampling_rate": 0.0, |
| 180 | + "order_id": "order_id_value", // highlight-line |
| 181 | + "message": "Collecting payment" |
| 182 | +} |
| 183 | +``` |
| 184 | +</details> |
| 185 | + |
| 186 | +## Sampling debug logs |
| 187 | + |
| 188 | +You can dynamically set a percentage of your logs to **DEBUG** level using `sample_rate` param or via env var `POWERTOOLS_LOGGER_SAMPLE_RATE`. |
| 189 | + |
| 190 | +<Note type="warning"> |
| 191 | + This is possible due to <a href="https://docs.aws.amazon.com/lambda/latest/dg/runtimes-context.html">AWS Lambda reuse of execution context</a>, <strong>however, it is not always guaranteed.</strong> |
| 192 | +</Note><br/> |
| 193 | + |
| 194 | +```python:title=collect.py |
| 195 | +from aws_lambda_powertools.logging import Logger |
| 196 | + |
| 197 | +# Sample 1% of debug logs e.g. 0.1 |
| 198 | +logger = Logger(sample_rate=0.1) # highlight-line |
| 199 | + |
| 200 | +def handler(event, context) |
| 201 | + if "order_id" in event: |
| 202 | + logger.info("Collecting payment") |
| 203 | + ... |
| 204 | +``` |
| 205 | + |
| 206 | +<details> |
| 207 | +<summary><strong>Exerpt output in CloudWatch Logs</strong></summary> |
| 208 | + |
| 209 | +```json:title=cloudwatch_logs.json |
| 210 | +{ |
| 211 | + "timestamp": "2020-05-24 18:17:33,774", |
| 212 | + "level": "INFO", |
| 213 | + "location": "collect.handler:1", |
| 214 | + "service": "payment", |
| 215 | + "lambda_function_name": "test", |
| 216 | + "lambda_function_memory_size": 128, |
| 217 | + "lambda_function_arn": "arn:aws:lambda:eu-west-1:12345678910:function:test", |
| 218 | + "lambda_request_id": "52fdfc07-2182-154f-163f-5f0f9a621d72", |
| 219 | + "cold_start": true, |
| 220 | + "sampling_rate": 0.1, // highlight-line |
| 221 | + "message": "Collecting payment" |
| 222 | +} |
| 223 | +``` |
| 224 | +</details> |
0 commit comments