55from typing import Optional , List , Callable , TYPE_CHECKING , Any
66
77from sentry_sdk .utils import format_timestamp , safe_repr
8- from sentry_sdk .envelope import Envelope
8+ from sentry_sdk .envelope import Envelope , Item , PayloadRef
99
1010if TYPE_CHECKING :
1111 from sentry_sdk ._types import Log
@@ -97,34 +97,36 @@ def flush(self):
9797 self ._flush ()
9898
9999 @staticmethod
100- def _log_to_otel (log ):
100+ def _log_to_transport_format (log ):
101101 # type: (Log) -> Any
102- def format_attribute (key , val ):
103- # type: (str, int | float | str | bool) -> Any
102+ def format_attribute (val ):
103+ # type: (int | float | str | bool) -> Any
104104 if isinstance (val , bool ):
105- return {"key " : key , "value " : { "boolValue" : val } }
105+ return {"value " : val , "type " : "boolean" }
106106 if isinstance (val , int ):
107- return {"key " : key , "value " : { "intValue" : str ( val )} }
107+ return {"value " : val , "type " : "integer" }
108108 if isinstance (val , float ):
109- return {"key " : key , "value " : { "doubleValue" : val } }
109+ return {"value " : val , "type " : "double" }
110110 if isinstance (val , str ):
111- return {"key" : key , "value" : {"stringValue" : val }}
112- return {"key" : key , "value" : {"stringValue" : safe_repr (val )}}
113-
114- otel_log = {
115- "severityText" : log ["severity_text" ],
116- "severityNumber" : log ["severity_number" ],
117- "body" : {"stringValue" : log ["body" ]},
118- "timeUnixNano" : str (log ["time_unix_nano" ]),
119- "attributes" : [
120- format_attribute (k , v ) for (k , v ) in log ["attributes" ].items ()
121- ],
111+ return {"value" : val , "type" : "string" }
112+ return {"value" : safe_repr (val ), "type" : "string" }
113+
114+ if "sentry.severity_number" not in log ["attributes" ]:
115+ log ["attributes" ]["sentry.severity_number" ] = log ["severity_number" ]
116+ if "sentry.severity_text" not in log ["attributes" ]:
117+ log ["attributes" ]["sentry.severity_text" ] = log ["severity_text" ]
118+
119+ res = {
120+ "timestamp" : int (log ["time_unix_nano" ]) / 1.0e9 ,
121+ "trace_id" : log .get ("trace_id" , "00000000-0000-0000-0000-000000000000" ),
122+ "level" : str (log ["severity_text" ]),
123+ "body" : str (log ["body" ]),
124+ "attributes" : {
125+ k : format_attribute (v ) for (k , v ) in log ["attributes" ].items ()
126+ },
122127 }
123128
124- if "trace_id" in log :
125- otel_log ["traceId" ] = log ["trace_id" ]
126-
127- return otel_log
129+ return res
128130
129131 def _flush (self ):
130132 # type: (...) -> Optional[Envelope]
@@ -133,10 +135,27 @@ def _flush(self):
133135 headers = {"sent_at" : format_timestamp (datetime .now (timezone .utc ))}
134136 )
135137 with self ._lock :
136- for log in self ._log_buffer :
137- envelope .add_log (self ._log_to_otel (log ))
138+ if len (self ._log_buffer ) == 0 :
139+ return None
140+
141+ envelope .add_item (
142+ Item (
143+ type = "log" ,
144+ content_type = "application/vnd.sentry.items.log+json" ,
145+ headers = {
146+ "item_count" : len (self ._log_buffer ),
147+ },
148+ payload = PayloadRef (
149+ json = {
150+ "items" : [
151+ self ._log_to_transport_format (log )
152+ for log in self ._log_buffer
153+ ]
154+ }
155+ ),
156+ )
157+ )
138158 self ._log_buffer .clear ()
139- if envelope .items :
140- self ._capture_func (envelope )
141- return envelope
142- return None
159+
160+ self ._capture_func (envelope )
161+ return envelope
0 commit comments