1- from __future__ import annotations
2-
31# Copyright 2025 Google LLC
42#
53# Licensed under the Apache License, Version 2.0 (the "License");
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+
1616import datetime
1717import logging
1818import urllib .parse
3838from opentelemetry .sdk ._logs import LogData
3939from opentelemetry .sdk ._logs .export import LogExporter
4040from opentelemetry .sdk .resources import Resource
41+ from opentelemetry .trace import format_span_id , format_trace_id
4142
4243DEFAULT_MAX_ENTRY_SIZE = 256000 # 256 KB
4344DEFAULT_MAX_REQUEST_SIZE = 10000000 # 10 MB
6263# severityMapping maps the integer severity level values from OTel [0-24]
6364# to matching Cloud Logging severity levels.
6465SEVERITY_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
0 commit comments