Skip to content
This repository was archived by the owner on Sep 17, 2025. It is now read-only.

Commit 22c1a28

Browse files
xinyi-joffrelzchen
authored andcommitted
Add custom_dimensions using kwargs instead of args (#837)
1 parent 157af58 commit 22c1a28

File tree

4 files changed

+70
-12
lines changed

4 files changed

+70
-12
lines changed

contrib/opencensus-ext-azure/README.rst

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -73,9 +73,9 @@ You can enrich the logs with trace IDs and span IDs by using the `logging integr
7373
logger.warning('In the span')
7474
logger.warning('After the span')
7575
76-
You can also add custom properties to your log messages in the form of key-values.
76+
You can also add custom properties to your log messages in the *extra* keyword argument using the custom_dimensions field.
7777

78-
WARNING: For this feature to work, you need to pass a dictionary as the argument. If you pass arguments of any other type, the logger will ignore them. The solution is to convert these arguments into a dictionary.
78+
WARNING: For this feature to work, you need to pass a dictionary to the custom_dimensions field. If you pass arguments of any other type, the logger will ignore them.
7979

8080
.. code:: python
8181
@@ -85,7 +85,9 @@ WARNING: For this feature to work, you need to pass a dictionary as the argument
8585
8686
logger = logging.getLogger(__name__)
8787
logger.addHandler(AzureLogHandler(connection_string='InstrumentationKey=<your-instrumentation_key-here>'))
88-
logger.warning('action', {'key-1': 'value-1', 'key-2': 'value2'})
88+
89+
properties = {'custom_dimensions': {'key_1': 'value_1', 'key_2': 'value_2'}}
90+
logger.warning('action', extra=properties)
8991
9092
Metrics
9193
~~~~~~~

contrib/opencensus-ext-azure/examples/logs/properties.py

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,4 +21,14 @@
2121
# and place it in the APPLICATIONINSIGHTS_CONNECTION_STRING
2222
# environment variable.
2323
logger.addHandler(AzureLogHandler())
24-
logger.warning('action', {'key-1': 'value-1', 'key-2': 'value2'})
24+
25+
properties = {'custom_dimensions': {'key_1': 'value_1', 'key_2': 'value_2'}}
26+
27+
# Use properties in logging statements
28+
logger.warning('action', extra=properties)
29+
30+
# Use properties in exception logs
31+
try:
32+
result = 1 / 0 # generate a ZeroDivisionError
33+
except Exception:
34+
logger.exception('Captured an exception.', extra=properties)

contrib/opencensus-ext-azure/opencensus/ext/azure/log_exporter/__init__.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,7 @@ def log_record_to_envelope(self, record):
153153
tags=dict(utils.azure_monitor_context),
154154
time=utils.timestamp_to_iso_str(record.created),
155155
)
156+
156157
envelope.tags['ai.operation.id'] = getattr(
157158
record,
158159
'traceId',
@@ -169,6 +170,11 @@ def log_record_to_envelope(self, record):
169170
'lineNumber': record.lineno,
170171
'level': record.levelname,
171172
}
173+
174+
if (hasattr(record, 'custom_dimensions') and
175+
isinstance(record.custom_dimensions, dict)):
176+
properties.update(record.custom_dimensions)
177+
172178
if record.exc_info:
173179
exctype, _value, tb = record.exc_info
174180
callstack = []
@@ -198,8 +204,6 @@ def log_record_to_envelope(self, record):
198204
)
199205
envelope.data = Data(baseData=data, baseType='ExceptionData')
200206
else:
201-
if isinstance(record.args, dict):
202-
properties.update(record.args)
203207
envelope.name = 'Microsoft.ApplicationInsights.Message'
204208
data = Message(
205209
message=self.format(record),

contrib/opencensus-ext-azure/tests/test_azure_log_exporter.py

Lines changed: 48 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,32 @@ def test_exception(self, requests_mock):
9595
post_body = requests_mock.call_args_list[0][1]['data']
9696
self.assertTrue('ZeroDivisionError' in post_body)
9797

98+
@mock.patch('requests.post', return_value=mock.Mock())
99+
def test_exception_with_custom_properties(self, requests_mock):
100+
logger = logging.getLogger(self.id())
101+
handler = log_exporter.AzureLogHandler(
102+
instrumentation_key='12345678-1234-5678-abcd-12345678abcd',
103+
storage_path=os.path.join(TEST_FOLDER, self.id()),
104+
)
105+
logger.addHandler(handler)
106+
try:
107+
return 1 / 0 # generate a ZeroDivisionError
108+
except Exception:
109+
properties = {
110+
'custom_dimensions':
111+
{
112+
'key_1': 'value_1',
113+
'key_2': 'value_2'
114+
}
115+
}
116+
logger.exception('Captured an exception.', extra=properties)
117+
handler.close()
118+
self.assertEqual(len(requests_mock.call_args_list), 1)
119+
post_body = requests_mock.call_args_list[0][1]['data']
120+
self.assertTrue('ZeroDivisionError' in post_body)
121+
self.assertTrue('key_1' in post_body)
122+
self.assertTrue('key_2' in post_body)
123+
98124
@mock.patch('requests.post', return_value=mock.Mock())
99125
def test_export_empty(self, request_mock):
100126
handler = log_exporter.AzureLogHandler(
@@ -143,12 +169,18 @@ def test_log_record_with_custom_properties(self, requests_mock):
143169
storage_path=os.path.join(TEST_FOLDER, self.id()),
144170
)
145171
logger.addHandler(handler)
146-
logger.warning('action', {'key-1': 'value-1', 'key-2': 'value-2'})
172+
logger.warning('action', extra={
173+
'custom_dimensions':
174+
{
175+
'key_1': 'value_1',
176+
'key_2': 'value_2'
177+
}
178+
})
147179
handler.close()
148180
post_body = requests_mock.call_args_list[0][1]['data']
149181
self.assertTrue('action' in post_body)
150-
self.assertTrue('key-1' in post_body)
151-
self.assertTrue('key-2' in post_body)
182+
self.assertTrue('key_1' in post_body)
183+
self.assertTrue('key_2' in post_body)
152184

153185
@mock.patch('requests.post', return_value=mock.Mock())
154186
def test_log_with_invalid_custom_properties(self, requests_mock):
@@ -159,9 +191,19 @@ def test_log_with_invalid_custom_properties(self, requests_mock):
159191
)
160192
logger.addHandler(handler)
161193
logger.warning('action_1_%s', None)
162-
logger.warning('action_2_%s', 'not_a_dict')
194+
logger.warning('action_2_%s', 'arg', extra={
195+
'custom_dimensions': 'not_a_dict'
196+
})
197+
logger.warning('action_3_%s', 'arg', extra={
198+
'notcustom_dimensions': {'key_1': 'value_1'}
199+
})
200+
163201
handler.close()
164202
self.assertEqual(len(os.listdir(handler.storage.path)), 0)
165203
post_body = requests_mock.call_args_list[0][1]['data']
166-
self.assertTrue('action_1' in post_body)
167-
self.assertTrue('action_2' in post_body)
204+
self.assertTrue('action_1_' in post_body)
205+
self.assertTrue('action_2_arg' in post_body)
206+
self.assertTrue('action_3_arg' in post_body)
207+
208+
self.assertFalse('not_a_dict' in post_body)
209+
self.assertFalse('key_1' in post_body)

0 commit comments

Comments
 (0)