rebrandly-otel 0.1.11__py3-none-any.whl → 0.1.13__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of rebrandly-otel might be problematic. Click here for more details.
- rebrandly_otel/rebrandly_otel.py +70 -56
- {rebrandly_otel-0.1.11.dist-info → rebrandly_otel-0.1.13.dist-info}/METADATA +1 -1
- {rebrandly_otel-0.1.11.dist-info → rebrandly_otel-0.1.13.dist-info}/RECORD +6 -6
- {rebrandly_otel-0.1.11.dist-info → rebrandly_otel-0.1.13.dist-info}/WHEEL +0 -0
- {rebrandly_otel-0.1.11.dist-info → rebrandly_otel-0.1.13.dist-info}/licenses/LICENSE +0 -0
- {rebrandly_otel-0.1.11.dist-info → rebrandly_otel-0.1.13.dist-info}/top_level.txt +0 -0
rebrandly_otel/rebrandly_otel.py
CHANGED
|
@@ -101,101 +101,115 @@ class RebrandlyOTEL:
|
|
|
101
101
|
|
|
102
102
|
# Fix for the lambda_handler method in rebrandly_otel.py
|
|
103
103
|
# Replace the lambda_handler method (around line 132) with this fixed version:
|
|
104
|
-
|
|
105
104
|
def lambda_handler(self,
|
|
106
105
|
name: Optional[str] = None,
|
|
107
106
|
attributes: Optional[Dict[str, Any]] = None,
|
|
108
|
-
kind: SpanKind = SpanKind.
|
|
107
|
+
kind: SpanKind = SpanKind.SERVER,
|
|
109
108
|
auto_flush: bool = True,
|
|
110
|
-
skip_aws_link: bool =
|
|
109
|
+
skip_aws_link: bool = False):
|
|
111
110
|
"""
|
|
112
111
|
Decorator specifically for Lambda handlers with automatic flushing.
|
|
113
112
|
"""
|
|
114
113
|
def decorator(func):
|
|
115
114
|
@functools.wraps(func)
|
|
116
|
-
def wrapper(event=None,
|
|
115
|
+
def wrapper(event=None, lambda_context=None):
|
|
117
116
|
# Determine span name
|
|
118
117
|
span_name = name or f"lambda.{func.__name__}"
|
|
119
|
-
|
|
118
|
+
start_time = datetime.now()
|
|
120
119
|
|
|
121
120
|
# Build span attributes
|
|
122
121
|
span_attributes = attributes or {}
|
|
123
|
-
|
|
124
122
|
span_attributes['faas.trigger'] = self._detect_lambda_trigger(event)
|
|
125
123
|
|
|
126
124
|
# Add Lambda-specific attributes if context is available
|
|
127
|
-
if
|
|
125
|
+
if lambda_context is not None:
|
|
128
126
|
span_attributes.update({
|
|
129
|
-
"faas.execution": getattr(
|
|
130
|
-
"faas.id": getattr(
|
|
131
|
-
"
|
|
132
|
-
"
|
|
127
|
+
"faas.execution": getattr(lambda_context, 'aws_request_id', 'unknown'),
|
|
128
|
+
"faas.id": getattr(lambda_context, 'function_arn', 'unknown'),
|
|
129
|
+
"faas.name": getattr(lambda_context, 'function_name', 'unknown'),
|
|
130
|
+
"faas.version": getattr(lambda_context, 'function_version', 'unknown')
|
|
133
131
|
})
|
|
134
132
|
|
|
133
|
+
# Handle context extraction from AWS events
|
|
134
|
+
token = None
|
|
135
|
+
if not skip_aws_link and event and isinstance(event, dict) and 'Records' in event:
|
|
136
|
+
first_record = event['Records'][0] if event['Records'] else None
|
|
137
|
+
if first_record:
|
|
138
|
+
carrier = {}
|
|
139
|
+
|
|
140
|
+
# Extract from SQS
|
|
141
|
+
if 'MessageAttributes' in first_record:
|
|
142
|
+
for key, value in first_record['MessageAttributes'].items():
|
|
143
|
+
if isinstance(value, dict) and 'StringValue' in value:
|
|
144
|
+
carrier[key] = value['StringValue']
|
|
145
|
+
|
|
146
|
+
# Extract from SNS
|
|
147
|
+
elif 'Sns' in first_record and 'MessageAttributes' in first_record['Sns']:
|
|
148
|
+
for key, value in first_record['Sns']['MessageAttributes'].items():
|
|
149
|
+
if isinstance(value, dict):
|
|
150
|
+
if 'Value' in value:
|
|
151
|
+
carrier[key] = value['Value']
|
|
152
|
+
elif 'StringValue' in value:
|
|
153
|
+
carrier[key] = value['StringValue']
|
|
154
|
+
|
|
155
|
+
# Attach extracted context
|
|
156
|
+
if carrier:
|
|
157
|
+
from opentelemetry import propagate, context as otel_context
|
|
158
|
+
extracted_context = propagate.extract(carrier)
|
|
159
|
+
token = otel_context.attach(extracted_context)
|
|
160
|
+
span_attributes['message.has_trace_context'] = True
|
|
161
|
+
|
|
135
162
|
result = None
|
|
136
163
|
try:
|
|
137
|
-
# Increment
|
|
164
|
+
# Increment invocation counter
|
|
138
165
|
self.meter.GlobalMetrics.invocations.add(1, {'function': span_name})
|
|
139
166
|
|
|
140
|
-
#
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
167
|
+
# Create and execute within span
|
|
168
|
+
with self.tracer.start_span(
|
|
169
|
+
name=span_name,
|
|
170
|
+
attributes=span_attributes,
|
|
171
|
+
kind=kind
|
|
172
|
+
) as span:
|
|
173
|
+
# Add invocation start event
|
|
174
|
+
span.add_event("lambda.invocation.start", {
|
|
175
|
+
'event.type': type(event).__name__ if event else 'None'
|
|
176
|
+
})
|
|
177
|
+
|
|
178
|
+
# Execute handler
|
|
179
|
+
result = func(event, lambda_context)
|
|
144
180
|
|
|
145
|
-
#
|
|
146
|
-
|
|
147
|
-
# SQS format
|
|
148
|
-
extracted_context = self.extract_context(first_record)
|
|
149
|
-
elif 'Sns' in first_record and 'MessageAttributes' in first_record['Sns']:
|
|
150
|
-
# SNS format
|
|
151
|
-
extracted_context = self.extract_context(first_record)
|
|
152
|
-
|
|
153
|
-
# Create span - use extracted context if available
|
|
154
|
-
if extracted_context:
|
|
155
|
-
token = self.attach_context(extracted_context)
|
|
156
|
-
try:
|
|
157
|
-
with self.span(span_name, attributes=span_attributes, kind=kind) as span_context:
|
|
158
|
-
# Add event type as span event
|
|
159
|
-
if event is not None:
|
|
160
|
-
span_context.add_event("lambda.invocation.start",
|
|
161
|
-
attributes={"event.type": type(event).__name__})
|
|
162
|
-
|
|
163
|
-
result = func(event, context) if event is not None else func()
|
|
164
|
-
|
|
165
|
-
# Handle result
|
|
166
|
-
self._process_lambda_result(result, span_context, span_name)
|
|
167
|
-
finally:
|
|
168
|
-
self.detach_context(token)
|
|
169
|
-
else:
|
|
170
|
-
# No context extraction needed
|
|
171
|
-
with self.span(span_name, attributes=span_attributes, kind=kind) as span_context:
|
|
172
|
-
# Add event type as span event
|
|
173
|
-
if event is not None:
|
|
174
|
-
span_context.add_event("lambda.invocation.start",
|
|
175
|
-
attributes={"event.type": type(event).__name__})
|
|
176
|
-
|
|
177
|
-
result = func(event, context) if event is not None else func()
|
|
178
|
-
|
|
179
|
-
# Handle result
|
|
180
|
-
self._process_lambda_result(result, span_context, span_name)
|
|
181
|
+
# Process result
|
|
182
|
+
self._process_lambda_result(result, span, span_name)
|
|
181
183
|
|
|
182
184
|
return result
|
|
183
185
|
|
|
184
186
|
except Exception as e:
|
|
185
187
|
# Increment error counter
|
|
186
|
-
self.meter.GlobalMetrics.error_invocations.add(1, {
|
|
188
|
+
self.meter.GlobalMetrics.error_invocations.add(1, {
|
|
189
|
+
'function': span_name,
|
|
190
|
+
'error': type(e).__name__
|
|
191
|
+
})
|
|
187
192
|
|
|
188
|
-
# Log error
|
|
193
|
+
# Log error
|
|
189
194
|
self.logger.logger.error(f"Lambda execution failed: {e}", exc_info=True)
|
|
190
195
|
raise
|
|
191
196
|
|
|
192
197
|
finally:
|
|
198
|
+
# Always detach context if we attached it
|
|
199
|
+
if token is not None:
|
|
200
|
+
from opentelemetry import context as otel_context
|
|
201
|
+
otel_context.detach(token)
|
|
202
|
+
|
|
193
203
|
# Record duration
|
|
194
|
-
duration = (datetime.now() -
|
|
204
|
+
duration = (datetime.now() - start_time).total_seconds() * 1000
|
|
195
205
|
self.meter.GlobalMetrics.duration.record(duration, {'function': span_name})
|
|
196
206
|
|
|
207
|
+
# Force flush if enabled
|
|
197
208
|
if auto_flush:
|
|
198
|
-
self.
|
|
209
|
+
self.logger.logger.info(f"[OTEL] Lambda '{span_name}' completed in {duration:.2f}ms, flushing...")
|
|
210
|
+
flush_success = self.force_flush(timeout_millis=1000)
|
|
211
|
+
if not flush_success:
|
|
212
|
+
self.logger.logger.warning("[OTEL] Force flush may not have completed fully")
|
|
199
213
|
|
|
200
214
|
return wrapper
|
|
201
215
|
return decorator
|
|
@@ -2,10 +2,10 @@ rebrandly_otel/__init__.py,sha256=AHcEKWq4KRafIF_x_Y8jiIQ5crNG1nbEwdnlGaEP6js,28
|
|
|
2
2
|
rebrandly_otel/logs.py,sha256=92jaxzI5hCHnKHu3lsSAa7K_SPHQgL46AlQUESsYNds,3724
|
|
3
3
|
rebrandly_otel/metrics.py,sha256=57jwrn8e1u66BOO7fcFrmtE3Rpt4VDixG9I78K-zrUU,8537
|
|
4
4
|
rebrandly_otel/otel_utils.py,sha256=uJmfz2NspSnTVJXGKoaLUl1CYb0ow6VHKjmg2d_rdwg,1704
|
|
5
|
-
rebrandly_otel/rebrandly_otel.py,sha256=
|
|
5
|
+
rebrandly_otel/rebrandly_otel.py,sha256=cnWTDMH-z4n32HTxCbML0zedKhG5ZKPtkej5sL1epok,21438
|
|
6
6
|
rebrandly_otel/traces.py,sha256=v582WtJv3t4Bn92vlDyZouibHtgWNxdRo_XmQCmSOEA,7126
|
|
7
|
-
rebrandly_otel-0.1.
|
|
8
|
-
rebrandly_otel-0.1.
|
|
9
|
-
rebrandly_otel-0.1.
|
|
10
|
-
rebrandly_otel-0.1.
|
|
11
|
-
rebrandly_otel-0.1.
|
|
7
|
+
rebrandly_otel-0.1.13.dist-info/licenses/LICENSE,sha256=KMXHvTwP62S2q-SG7CFfMU_09rUwxiqlM0izaYGdcgY,1103
|
|
8
|
+
rebrandly_otel-0.1.13.dist-info/METADATA,sha256=Xu5Rxr80l_mB6Hx489zddCbWDqNKxcr6klUzujSV-4Y,9628
|
|
9
|
+
rebrandly_otel-0.1.13.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
10
|
+
rebrandly_otel-0.1.13.dist-info/top_level.txt,sha256=26PSC1gjVUl8tTH5QfKbFevjVV4E2yojoukEfiTScvM,15
|
|
11
|
+
rebrandly_otel-0.1.13.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|