5
5
from typing import Optional , List , Callable , TYPE_CHECKING , Any
6
6
7
7
from sentry_sdk .utils import format_timestamp , safe_repr
8
- from sentry_sdk .envelope import Envelope
8
+ from sentry_sdk .envelope import Envelope , Item , PayloadRef
9
9
10
10
if TYPE_CHECKING :
11
11
from sentry_sdk ._types import Log
@@ -97,34 +97,36 @@ def flush(self):
97
97
self ._flush ()
98
98
99
99
@staticmethod
100
- def _log_to_otel (log ):
100
+ def _log_to_transport_format (log ):
101
101
# 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
104
104
if isinstance (val , bool ):
105
- return {"key " : key , "value " : { "boolValue" : val } }
105
+ return {"value " : val , "type " : "boolean" }
106
106
if isinstance (val , int ):
107
- return {"key " : key , "value " : { "intValue" : str ( val )} }
107
+ return {"value " : val , "type " : "integer" }
108
108
if isinstance (val , float ):
109
- return {"key " : key , "value " : { "doubleValue" : val } }
109
+ return {"value " : val , "type " : "double" }
110
110
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
+ },
122
127
}
123
128
124
- if "trace_id" in log :
125
- otel_log ["traceId" ] = log ["trace_id" ]
126
-
127
- return otel_log
129
+ return res
128
130
129
131
def _flush (self ):
130
132
# type: (...) -> Optional[Envelope]
@@ -133,10 +135,27 @@ def _flush(self):
133
135
headers = {"sent_at" : format_timestamp (datetime .now (timezone .utc ))}
134
136
)
135
137
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
+ )
138
158
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