Skip to content

Commit 9cca95c

Browse files
committed
docs(quickstart): same process for Logger
1 parent 6584364 commit 9cca95c

File tree

1 file changed

+61
-26
lines changed

1 file changed

+61
-26
lines changed

docs/quickstart.md

Lines changed: 61 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -362,10 +362,16 @@ From here, we could handle [404 routes](./core/event_handler/api_gateway.md#hand
362362
!!! tip
363363
If you'd like to learn how python decorators work under the hood, you can follow [Real Python](https://realpython.com/primer-on-python-decorators/)'s article.
364364
## Structured Logging
365-
In the next step, you decided to propose production quality logging capabilities to your Lambda code.
366-
We want our log event to be in a JSON format. Also, You follow [structured logging approach](https://docs.aws.amazon.com/lambda/latest/operatorguide/parse-logs.html). In a result, we expect easy to search, consistent logs containing enough context and data to analyse the status of our system. We can take advantage of CloudWatch Logs and Cloudwatch Insight for this purpose.
367365

368-
The first option could be to use a python logger in combination with the `pythonjsonlogger` library for simple structured logging.
366+
Over time, you realize that searching logs as text results in poor observability, it's hard to create metrics from, enumerate common exceptions, etc.
367+
368+
Then, you decided to propose production quality logging capabilities to your Lambda code. You found out that by having logs as `JSON` you can [structure them](https://docs.aws.amazon.com/lambda/latest/operatorguide/parse-logs.html), so that you can use any Log Analytics tool out there to quickly analyze them.
369+
370+
This helps not only in searching, but produces consistent logs containing enough context and data to ask arbitrary questions on the status of your system. We can take advantage of CloudWatch Logs and Cloudwatch Insight for this purpose.
371+
372+
### Logs as JSON with pythonjsonlogger
373+
374+
The first option could be to use the standard Python Logger, and use a specialized library like `pythonjsonlogger` to create a JSON Formatter.
369375

370376
=== "app.py"
371377

@@ -378,7 +384,7 @@ The first option could be to use a python logger in combination with the `python
378384

379385
from aws_lambda_powertools.event_handler.api_gateway import ApiGatewayResolver
380386

381-
logger = logging.getLogger("APP")
387+
logger = logging.getLogger("hello")
382388
logHandler = logging.StreamHandler()
383389
formatter = jsonlogger.JsonFormatter(fmt="%(asctime)s %(levelname)s %(name)s %(message)s")
384390
logHandler.setFormatter(formatter)
@@ -410,35 +416,54 @@ The first option could be to use a python logger in combination with the `python
410416
aws-lambda-powertools
411417
python-json-logger
412418
```
413-
On the first try, we do a couple of steps to set up our logging:
414419

415-
* Create an application logger called `APP`.
416-
* Configure handler and formatter.
417-
* Set log level.
420+
With just a few lines our logs will now output to `JSON` format. We've taken the following steps to make that work:
421+
422+
* **L9**: Creates an application logger named `hello`
423+
* **L10-13**: Configures handler and formatter
424+
* **L14**: Sets the logging level set in the `LOG_LEVEL` environment variable, or `INFO` as a sentinel value
418425

419426
After that, we use this logger in our application code to record the required information. We see logs structured as follows:
420-
```json
421-
{"asctime": "2021-11-22 15:32:02,145", "levelname": "INFO", "name": "APP", "message": "Request from unknown received"}
422-
```
423-
instead of
424-
```json
425-
[INFO] 2021-11-22T15:32:02.145Z ba3bea3d-fe3a-45db-a2ce-72e813d55b91 Request from unknown received
426-
```
427427

428-
So far, so good! To make things easier, we want to add extra context to the logs.
429-
We can extract it from a Lambda context or an event passed to Lambda handler at the time of invocation. We add those specific attributes wherever a logger is used.
428+
=== "JSON output"
429+
430+
```json
431+
{
432+
"asctime": "2021-11-22 15:32:02,145",
433+
"levelname": "INFO",
434+
"name": "hello",
435+
"message": "Request from unknown received"
436+
}
437+
```
438+
439+
=== "Normal output"
440+
441+
```python
442+
[INFO] 2021-11-22T15:32:02.145Z ba3bea3d-fe3a-45db-a2ce-72e813d55b91 Request from unknown received
443+
```
444+
445+
So far, so good! We can take a step further now by adding additional context to the logs.
446+
447+
We could start by creating a dictionary with Lambda context information or something from the incoming event, which should always be logged. Additional attributes could be added on every `logger.info` using `extra` keyword like in any standard Python logger.
448+
449+
450+
### Simplifying with Logger
451+
452+
???+ question "Surely this could be easier, right?"
453+
Yes! Powertools Logger to the rescue :-)
454+
455+
As we already have Lambda Powertools as a dependency, we can simply import [Logger](./core/logger.md){target="_blank"}.
430456

431-
Can we ensure that the required attributes are added automatically on our behalf without having to move them around? Yes! Powertools Logger to the rescue :-)
432457
=== "app.py"
433458

434-
```python hl_lines="3 7 14 20 24"
459+
```python hl_lines="3 5 7 14 20 24"
435460
import json
436461

437462
from aws_lambda_powertools import Logger
438463
from aws_lambda_powertools.event_handler.api_gateway import ApiGatewayResolver
439464
from aws_lambda_powertools.logging import correlation_paths
440465

441-
logger = Logger(service="APP")
466+
logger = Logger(service="order")
442467

443468
app = ApiGatewayResolver()
444469

@@ -460,12 +485,18 @@ Can we ensure that the required attributes are added automatically on our behalf
460485
return app.resolve(event, context)
461486
```
462487

463-
We add powertools logger (line 8) and all the configuration is done.
464-
We also use `logger.inject_lambda_context` decorator to inject Lambda context into every log. We instruct logger to log correlation id taken from API Gateway and event automatically. Because powertools library adds a correlation identifier to each log, we can easily correlate all the logs generated for a specific request.
488+
Let's break this down:
465489

466-
In result, we should see logs with following attributes.
467-
=== "Example Application Structured Log"
468-
```json
490+
* **L8**: We add Lambda Powertools Logger; the boilerplate is now done for you. By default, we set `INFO` as the logging level if `LOG_LEVEL` env var isn't set
491+
* **L24**: We use `logger.inject_lambda_context` decorator to inject key information from Lambda context into every log.
492+
* **L24**: We also instruct Logger to use the incoming API Gateway Request ID as a [correlation id](./core/logger.md##set_correlation_id-method) automatically.
493+
* **L24**: Since we're in dev, we also use `log_event=True` to automatically log each incoming request for debugging. This can be also set via [environment variables](./index.md#environment-variables){target="_blank"}.
494+
495+
We can now search our logs by the request ID to find a specific operation. Additionally, we can also search our logs for function name, Lambda request ID, Lambda function ARN, find out whether an operation was a cold start, etc.
496+
497+
This is how the logs would look like now:
498+
499+
```json title="Our logs are now structured consistently"
469500
{
470501
"level":"INFO",
471502
"location":"hello:17",
@@ -481,7 +512,11 @@ In result, we should see logs with following attributes.
481512
"correlation_id":"bf9b584c-e5d9-4ad5-af3d-db953f2b10dc"
482513
}
483514
```
484-
By having structured logs like this, we can easily search and analyse them in [CloudWatch Logs Insight](https://docs.aws.amazon.com/AmazonCloudWatch/latest/logs/AnalyzingLogData.html).
515+
516+
From here, we could [set specific keys](./core/logger.md#append_keys-method){target="_blank"} to add additional contextual information about a given operation, [log exceptions](./core/logger.md#logging-exceptions){target="_blank"} to easily enumerate them later, [sample debug logs](./core/logger.md#sampling-debug-logs){target="_blank"}, etc.
517+
518+
By having structured logs like this, we can easily search and analyse them in [CloudWatch Logs Insight](https://docs.aws.amazon.com/AmazonCloudWatch/latest/logs/AnalyzingLogData.html){target="_blank"}.
519+
485520
=== "CloudWatch Logs Insight Example"
486521
![CloudWatch Logs Insight Example](./media/cloudwatch_logs_insight_example.png)
487522
## Tracing

0 commit comments

Comments
 (0)