Skip to content

Commit 6f64cd4

Browse files
committed
feature: ability to pass sampling_rate to logger setup so calls may get sampled in "debug" setup.
1 parent f25f625 commit 6f64cd4

File tree

3 files changed

+55
-19
lines changed

3 files changed

+55
-19
lines changed

.gitignore

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -291,5 +291,5 @@ $RECYCLE.BIN/
291291
# End of https://www.gitignore.io/api/osx,linux,python,windows,pycharm,visualstudiocode
292292

293293
# Misc
294-
295-
test_report
294+
test_report
295+
/.idea/*

python/aws_lambda_powertools/logging/logger.py

Lines changed: 34 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,19 +2,22 @@
22
import itertools
33
import logging
44
import os
5+
import random
56
from distutils.util import strtobool
67
from typing import Any, Callable, Dict
78

8-
from . import aws_lambda_logging
99
from ..helper.models import MetricUnit, build_lambda_context_model, build_metric_unit_from_str
10+
from . import aws_lambda_logging
1011

1112
logger = logging.getLogger(__name__)
1213
logger.setLevel(os.getenv("LOG_LEVEL", "INFO"))
1314

1415
is_cold_start = True
1516

1617

17-
def logger_setup(service: str = "service_undefined", level: str = "INFO", **kwargs):
18+
def logger_setup(
19+
service: str = "service_undefined", level: str = "INFO", sampling_rate: float = 0.0, **kwargs
20+
):
1821
"""Setups root logger to format statements in JSON.
1922
2023
Includes service name and any additional key=value into logs
@@ -26,13 +29,17 @@ def logger_setup(service: str = "service_undefined", level: str = "INFO", **kwar
2629
service name
2730
LOG_LEVEL: str
2831
logging level (e.g. INFO, DEBUG)
32+
POWERTOOLS_SAMPLE_RATE: str
33+
samping rate ranging from 0 to 1, float precision
2934
3035
Parameters
3136
----------
3237
service : str, optional
3338
service name to be appended in logs, by default "service_undefined"
3439
level : str, optional
3540
logging.level, by default "INFO"
41+
sample_rate: float, optional
42+
sample rate for debug calls within execution context defaults to 0
3643
3744
Example
3845
-------
@@ -52,21 +59,36 @@ def logger_setup(service: str = "service_undefined", level: str = "INFO", **kwar
5259
>>>
5360
>>> def handler(event, context):
5461
logger.info("Hello")
62+
:param service:
63+
:param level:
64+
:param sampling_rate:
5565
5666
"""
5767
service = os.getenv("POWERTOOLS_SERVICE_NAME") or service
68+
sampling_rate = os.getenv("POWERTOOLS_SAMPLE_RATE") or sampling_rate
5869
log_level = os.getenv("LOG_LEVEL") or level
5970
logger = logging.getLogger(name=service)
71+
72+
# sampling a small percentage of requests with debug level, using a float value 0.1 = 10%~
73+
74+
try:
75+
if sampling_rate and random.random() <= float(sampling_rate):
76+
log_level = logging.DEBUG
77+
except ValueError:
78+
logger.debug("POWERTOOLS_SAMPLE_RATE provided value {0} is not valid.".format(sampling_rate))
79+
6080
logger.setLevel(log_level)
6181

6282
# Patch logger by structuring its outputs as JSON
63-
aws_lambda_logging.setup(level=log_level, service=service, **kwargs)
83+
aws_lambda_logging.setup(
84+
level=log_level, service=service, sampling_rate=sampling_rate, **kwargs
85+
)
6486

6587
return logger
6688

6789

6890
def logger_inject_lambda_context(
69-
lambda_handler: Callable[[Dict, Any], Any] = None, log_event: bool = False
91+
lambda_handler: Callable[[Dict, Any], Any] = None, log_event: bool = False
7092
):
7193
"""Decorator to capture Lambda contextual info and inject into struct logging
7294
@@ -110,6 +132,8 @@ def logger_inject_lambda_context(
110132
-------
111133
decorate : Callable
112134
Decorated lambda handler
135+
:param log_event:
136+
:param lambda_handler:
113137
"""
114138

115139
# If handler is None we've been called with parameters
@@ -159,12 +183,12 @@ def __is_cold_start() -> str:
159183

160184

161185
def log_metric(
162-
name: str,
163-
namespace: str,
164-
unit: MetricUnit,
165-
value: float = 0,
166-
service: str = "service_undefined",
167-
**dimensions,
186+
name: str,
187+
namespace: str,
188+
unit: MetricUnit,
189+
value: float = 0,
190+
service: str = "service_undefined",
191+
**dimensions,
168192
):
169193
"""Logs a custom metric in a statsD-esque format to stdout.
170194

python/tests/functional/test_logger.py

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,19 @@ def test_setup_service_env_var(monkeypatch, root_logger, stdout):
8080
assert service_name == log["service"]
8181

8282

83+
def test_setup_sampling_rate(monkeypatch, root_logger, stdout):
84+
# GIVEN samping rate is explicitly defined via POWERTOOLS_SAMPLE_RATE env
85+
# WHEN logger is setup
86+
# THEN sampling rate should be equals POWERTOOLS_SAMPLE_RATE value
87+
sampling_rate = "0.1"
88+
monkeypatch.setenv("POWERTOOLS_SAMPLE_RATE", sampling_rate)
89+
90+
logger = logger_setup()
91+
logger.info("Hello")
92+
log = json.loads(stdout.getvalue())
93+
assert sampling_rate == log["sampling_rate"]
94+
95+
8396
def test_inject_lambda_context(root_logger, stdout, lambda_context):
8497
# GIVEN a lambda function is decorated with logger
8598
# WHEN logger is setup
@@ -128,9 +141,8 @@ def handler(event, context):
128141

129142

130143
def test_inject_lambda_context_log_event_request_env_var(
131-
monkeypatch, root_logger, stdout, lambda_context
144+
monkeypatch, root_logger, stdout, lambda_context
132145
):
133-
134146
# GIVEN a lambda function is decorated with logger instructed to log event
135147
# via POWERTOOLS_LOGGER_LOG_EVENT env
136148
# WHEN logger is setup
@@ -160,7 +172,7 @@ def handler(event, context):
160172

161173

162174
def test_inject_lambda_context_log_no_request_by_default(
163-
monkeypatch, root_logger, stdout, lambda_context
175+
monkeypatch, root_logger, stdout, lambda_context
164176
):
165177
# GIVEN a lambda function is decorated with logger
166178
# WHEN logger is setup
@@ -281,12 +293,12 @@ def test_log_metric_multiple_dimensions(capsys):
281293
"invalid_input,expected",
282294
[
283295
(
284-
{"unit": "seconds"},
285-
"MONITORING|0|Seconds|test_metric|DemoApp|service=service_undefined\n",
296+
{"unit": "seconds"},
297+
"MONITORING|0|Seconds|test_metric|DemoApp|service=service_undefined\n",
286298
),
287299
(
288-
{"unit": "Seconds", "customer": None, "charge_id": "123", "payment_status": ""},
289-
"MONITORING|0|Seconds|test_metric|DemoApp|service=service_undefined,charge_id=123\n",
300+
{"unit": "Seconds", "customer": None, "charge_id": "123", "payment_status": ""},
301+
"MONITORING|0|Seconds|test_metric|DemoApp|service=service_undefined,charge_id=123\n",
290302
),
291303
],
292304
ids=["metric unit as string lower case", "empty dimension value"],

0 commit comments

Comments
 (0)