Skip to content

Commit bc51c25

Browse files
committed
Address comments in PR.
1 parent 219e9f7 commit bc51c25

File tree

3 files changed

+73
-80
lines changed

3 files changed

+73
-80
lines changed

opentelemetry-exporter-gcp-logging/README.rst

Lines changed: 26 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -35,22 +35,39 @@ Usage
3535
-----
3636

3737
.. code:: python
38-
38+
import logging
3939
from opentelemetry.exporter.cloud_logging import (
4040
CloudLoggingExporter,
4141
)
4242
from opentelemetry.sdk._logs._internal import LogRecord
4343
from opentelemetry._logs.severity import SeverityNumber
4444
from opentelemetry.sdk.resources import Resource
45-
from opentelemetry.sdk._logs import LogData
46-
from opentelemetry.sdk.util.instrumentation import InstrumentationScope
45+
from opentelemetry._logs import set_logger_provider
46+
from opentelemetry.sdk._logs import LoggerProvider, LoggingHandler
47+
from opentelemetry.sdk._logs.export import BatchLogRecordProcessor
48+
49+
logger_provider = LoggerProvider(
50+
resource=Resource.create(
51+
{
52+
"service.name": "shoppingcart",
53+
"service.instance.id": "instance-12",
54+
}
55+
),
56+
)
57+
set_logger_provider(logger_provider)
58+
exporter = CloudLoggingExporter(default_log_name='my_log')
59+
logger_provider.add_log_record_processor(BatchLogRecordProcessor(exporter))
60+
handler = LoggingHandler(level=logging.NOTSET, logger_provider=logger_provider)
4761
62+
# Attach OTLP handler to root logger
63+
logging.getLogger().addHandler(handler)
4864
49-
exporter = CloudLoggingExporter(default_log_name='my_log')
50-
exporter.export(
51-
[
52-
LogData(
53-
log_record=LogRecord(
65+
# Create namespaced logger
66+
# It is recommended to not use the root logger with OTLP handler
67+
# so telemetry is collected only for the application
68+
logger1 = logging.getLogger("myapp.area1")
69+
70+
logger1.debug(LogRecord(
5471
resource=Resource({}),
5572
timestamp=1736976310997977393,
5673
severity_number=SeverityNumber(20),
@@ -68,12 +85,7 @@ Usage
6885
]
6986
}
7087
},
71-
),
72-
instrumentation_scope=InstrumentationScope("test"),
73-
)
74-
]
75-
)
76-
88+
))
7789
7890
References
7991
----------

opentelemetry-exporter-gcp-logging/src/opentelemetry/exporter/cloud_logging/__init__.py

Lines changed: 45 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
from __future__ import annotations
2-
31
# Copyright 2025 Google LLC
42
#
53
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -13,6 +11,8 @@
1311
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1412
# See the License for the specific language governing permissions and
1513
# limitations under the License.
14+
from __future__ import annotations
15+
1616
import datetime
1717
import logging
1818
import urllib.parse
@@ -38,6 +38,7 @@
3838
from opentelemetry.sdk._logs import LogData
3939
from opentelemetry.sdk._logs.export import LogExporter
4040
from opentelemetry.sdk.resources import Resource
41+
from opentelemetry.trace import format_span_id, format_trace_id
4142

4243
DEFAULT_MAX_ENTRY_SIZE = 256000 # 256 KB
4344
DEFAULT_MAX_REQUEST_SIZE = 10000000 # 10 MB
@@ -62,31 +63,31 @@
6263
# severityMapping maps the integer severity level values from OTel [0-24]
6364
# to matching Cloud Logging severity levels.
6465
SEVERITY_MAPPING: dict[int, int] = {
65-
0: LogSeverity.DEFAULT, # Default, 0
66-
1: LogSeverity.DEBUG, #
67-
2: LogSeverity.DEBUG, #
68-
3: LogSeverity.DEBUG, #
69-
4: LogSeverity.DEBUG, #
70-
5: LogSeverity.DEBUG, #
71-
6: LogSeverity.DEBUG, #
72-
7: LogSeverity.DEBUG, #
73-
8: LogSeverity.DEBUG, # 1-8 -> Debug
74-
9: LogSeverity.INFO, #
75-
10: LogSeverity.INFO, # 9-10 -> Info
76-
11: LogSeverity.NOTICE, #
77-
12: LogSeverity.NOTICE, # 11-12 -> Notice
78-
13: LogSeverity.WARNING, #
79-
14: LogSeverity.WARNING, #
80-
15: LogSeverity.WARNING, #
81-
16: LogSeverity.WARNING, # 13-16 -> Warning
82-
17: LogSeverity.ERROR, #
83-
18: LogSeverity.ERROR, #
84-
19: LogSeverity.ERROR, #
85-
20: LogSeverity.ERROR, # 17-20 -> Error
86-
21: LogSeverity.CRITICAL, #
87-
22: LogSeverity.CRITICAL, # 21-22 -> Critical
88-
23: LogSeverity.ALERT, # 23 -> Alert
89-
24: LogSeverity.EMERGENCY, # 24 -> Emergency
66+
0: LogSeverity.DEFAULT,
67+
1: LogSeverity.DEBUG,
68+
2: LogSeverity.DEBUG,
69+
3: LogSeverity.DEBUG,
70+
4: LogSeverity.DEBUG,
71+
5: LogSeverity.DEBUG,
72+
6: LogSeverity.DEBUG,
73+
7: LogSeverity.DEBUG,
74+
8: LogSeverity.DEBUG,
75+
9: LogSeverity.INFO,
76+
10: LogSeverity.INFO,
77+
11: LogSeverity.NOTICE,
78+
12: LogSeverity.NOTICE,
79+
13: LogSeverity.WARNING,
80+
14: LogSeverity.WARNING,
81+
15: LogSeverity.WARNING,
82+
16: LogSeverity.WARNING,
83+
17: LogSeverity.ERROR,
84+
18: LogSeverity.ERROR,
85+
19: LogSeverity.ERROR,
86+
20: LogSeverity.ERROR,
87+
21: LogSeverity.CRITICAL,
88+
22: LogSeverity.CRITICAL,
89+
23: LogSeverity.ALERT,
90+
24: LogSeverity.EMERGENCY,
9091
}
9192

9293

@@ -107,32 +108,29 @@ def __init__(
107108
self.default_log_name = default_log_name
108109
else:
109110
self.default_log_name = "otel_python_inprocess_log_name_temp"
110-
if default_log_name:
111-
self.default_log_name = default_log_name
112-
else:
113-
self.default_log_name = "otel_python_inprocess_log_name_temp"
114111
self.client = client or LoggingServiceV2Client(
115112
transport=LoggingServiceV2GrpcTransport(
116113
channel=LoggingServiceV2GrpcTransport.create_channel(
117114
options=_OPTIONS,
118115
)
119116
)
120117
)
121-
self.service_resource_labels = True
122118

123119
def export(self, batch: Sequence[LogData]):
120+
now = datetime.datetime.now()
124121
log_entries = []
125122
for log_data in batch:
126123
log_record = log_data.log_record
127124
attributes = log_record.attributes or {}
128-
project_id = self.project_id
129-
if attributes.get(PROJECT_ID_ATTRIBUTE_KEY):
130-
project_id = str(attributes.get(PROJECT_ID_ATTRIBUTE_KEY))
131-
log_name = self.default_log_name
132-
if attributes.get(LOG_NAME_ATTRIBUTE_KEY):
133-
log_name = str(attributes.get(LOG_NAME_ATTRIBUTE_KEY))
134-
monitored_resource_data = get_monitored_resource(
135-
log_record.resource or Resource({})
125+
project_id = str(
126+
attributes.get(PROJECT_ID_ATTRIBUTE_KEY, self.project_id)
127+
)
128+
log_suffix = urllib.parse.quote_plus(
129+
str(
130+
attributes.get(
131+
LOG_NAME_ATTRIBUTE_KEY, self.default_log_name
132+
)
133+
)
136134
)
137135
monitored_resource_data = get_monitored_resource(
138136
log_record.resource or Resource({})
@@ -146,44 +144,27 @@ def export(self, batch: Sequence[LogData]):
146144
if monitored_resource_data
147145
else None
148146
)
149-
# if timestamp is unset, fall back to observed_time_unix_nano as recommended
150-
# (see https://github.com/open-telemetry/opentelemetry-proto/blob/4abbb78/opentelemetry/proto/logs/v1/logs.proto#L176-L179)
147+
# If timestamp is unset fall back to observed_time_unix_nano as recommended,
148+
# see https://github.com/open-telemetry/opentelemetry-proto/blob/4abbb78/opentelemetry/proto/logs/v1/logs.proto#L176-L179
151149
ts = Timestamp()
152150
if log_record.timestamp or log_record.observed_timestamp:
153151
ts.FromNanoseconds(
154152
log_record.timestamp or log_record.observed_timestamp
155153
)
156154
else:
157-
ts.FromDatetime(datetime.datetime.now())
158-
log_name = "projects/{}/logs/{}".format(
159-
project_id, urllib.parse.quote_plus(log_name)
160-
)
155+
ts.FromDatetime(now)
156+
log_name = f"projects/{project_id}/logs/{log_suffix}"
161157
log_entry = LogEntry()
162158
log_entry.timestamp = ts
163159
log_entry.log_name = log_name
164-
if monitored_resource:
165-
log_entry.resource = monitored_resource
166160
if monitored_resource:
167161
log_entry.resource = monitored_resource
168162
attrs_map = {k: v for k, v in attributes.items()}
169-
log_entry.trace_sampled = (
170-
log_record.trace_flags is not None
171-
and log_record.trace_flags.sampled
172-
)
173-
if TRACE_SAMPLED_ATTRIBUTE_KEY in attrs_map:
174-
log_entry.trace_sampled |= bool(
175-
attrs_map[TRACE_SAMPLED_ATTRIBUTE_KEY]
176-
)
177-
log_entry.trace_sampled |= bool(
178-
attrs_map[TRACE_SAMPLED_ATTRIBUTE_KEY]
179-
)
180-
del attrs_map[TRACE_SAMPLED_ATTRIBUTE_KEY]
163+
log_entry.trace_sampled = bool(log_record.trace_flags)
181164
if log_record.trace_id:
182-
log_entry.trace = "projects/{}/traces/{}".format(
183-
project_id, log_record.trace_id
184-
)
165+
log_entry.trace = f"projects/{project_id}/traces/{format_trace_id(log_record.trace_id)}"
185166
if log_record.span_id:
186-
log_entry.span_id = str(hex(log_record.span_id))[2:]
167+
log_entry.span_id = format_span_id(log_record.span_id)
187168
if (
188169
log_record.severity_number
189170
and log_record.severity_number.value in SEVERITY_MAPPING

opentelemetry-exporter-gcp-logging/tests/__snapshots__/test_cloud_logging/test_convert_otlp.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,9 +28,9 @@
2828
"type": "generic_node"
2929
},
3030
"severity": "ERROR",
31-
"spanId": "16",
31+
"spanId": "0000000000000016",
3232
"timestamp": "2025-01-15T21:25:10.997977393Z",
33-
"trace": "projects/fakeproject/traces/25"
33+
"trace": "projects/fakeproject/traces/00000000000000000000000000000019"
3434
}
3535
]
3636
}

0 commit comments

Comments
 (0)