rebrandly-otel 0.1.8__py3-none-any.whl → 0.1.10__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/logs.py CHANGED
@@ -11,7 +11,7 @@ from opentelemetry.sdk._logs.export import (
11
11
  from opentelemetry.exporter.otlp.proto.grpc._log_exporter import OTLPLogExporter
12
12
  from opentelemetry._logs import set_logger_provider
13
13
 
14
- from otel_utils import *
14
+ from .otel_utils import *
15
15
 
16
16
 
17
17
  class RebrandlyLogger:
rebrandly_otel/metrics.py CHANGED
@@ -12,7 +12,7 @@ from opentelemetry.sdk.metrics.export import (PeriodicExportingMetricReader, Con
12
12
  from opentelemetry.sdk.metrics._internal.aggregation import (ExplicitBucketHistogramAggregation)
13
13
  from opentelemetry.sdk.metrics.view import View
14
14
 
15
- from otel_utils import *
15
+ from .otel_utils import *
16
16
 
17
17
  class MetricType(Enum):
18
18
  """Supported metric types."""
@@ -11,9 +11,9 @@ from opentelemetry.trace import Status, StatusCode, SpanKind
11
11
  from typing import Optional, Dict, Any, Callable, TypeVar
12
12
  from opentelemetry import baggage, propagate, context
13
13
 
14
- from traces import RebrandlyTracer
15
- from metrics import RebrandlyMeter
16
- from logs import RebrandlyLogger
14
+ from .traces import RebrandlyTracer
15
+ from .metrics import RebrandlyMeter
16
+ from .logs import RebrandlyLogger
17
17
 
18
18
 
19
19
  T = TypeVar('T')
@@ -99,6 +99,9 @@ class RebrandlyOTEL:
99
99
  return wrapper
100
100
  return decorator
101
101
 
102
+ # Fix for the lambda_handler method in rebrandly_otel.py
103
+ # Replace the lambda_handler method (around line 132) with this fixed version:
104
+
102
105
  def lambda_handler(self,
103
106
  name: Optional[str] = None,
104
107
  attributes: Optional[Dict[str, Any]] = None,
@@ -107,22 +110,6 @@ class RebrandlyOTEL:
107
110
  skip_aws_link: bool = True):
108
111
  """
109
112
  Decorator specifically for Lambda handlers with automatic flushing.
110
-
111
- Args:
112
- name: Optional span name (defaults to 'lambda.{function_name}')
113
- attributes: Additional span attributes
114
- kind: Span kind (defaults to SERVER)
115
- auto_flush: If True, automatically flush after handler completes
116
-
117
- Usage:
118
- @lambda_handler()
119
- def my_handler(event, context): ...
120
-
121
- @lambda_handler(name="custom_span_name")
122
- def my_handler(event, context): ...
123
-
124
- @lambda_handler(name="my_span", attributes={"env": "prod"})
125
- def my_handler(event, context): ...
126
113
  """
127
114
  def decorator(func):
128
115
  @functools.wraps(func)
@@ -150,50 +137,91 @@ class RebrandlyOTEL:
150
137
  # Increment invocations counter
151
138
  self.meter.GlobalMetrics.invocations.add(1, {'function': span_name})
152
139
 
153
- # Create span and execute function
154
- record = None
155
- span_function = self.span
156
- if not skip_aws_link and event is not None and 'Records' in event and len(event['Records']) > 0 and 'MessageAttributes' in event['Records'][0]:
157
- span_function = self.aws_message_span
158
- record = event['Records'][0]
159
-
160
- with span_function(span_name, message=record, attributes=span_attributes, kind=kind) as span_context:
161
- # Add event type as span event
162
- if event is not None:
163
- span_context.add_event("lambda.invocation.start", attributes={"event.type": type(event).__name__})
164
-
165
- result = func(event, context)
166
- else:
167
- result = func()
168
-
169
- # Add result information if applicable
170
- if isinstance(result, dict):
171
- if 'statusCode' in result:
172
- span_context.set_attribute("http.status_code", result['statusCode'])
173
- # Set span status based on HTTP status code
174
- if result['statusCode'] >= 400:
175
- span_context.set_status(Status(StatusCode.ERROR, f"HTTP {result['statusCode']}"))
176
- else:
177
- span_context.set_status(Status(StatusCode.OK))
178
-
179
- # Increment success counter
180
- self.meter.GlobalMetrics.successful_invocations.add(1, {'function': span_name})
181
-
182
- return result
140
+ # Determine if we should extract context from AWS message
141
+ extracted_context = None
142
+ if not skip_aws_link and event is not None and 'Records' in event and len(event['Records']) > 0:
143
+ first_record = event['Records'][0]
144
+
145
+ # Check different message formats
146
+ if 'messageAttributes' in first_record or 'MessageAttributes' in first_record:
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
+
182
+ return result
183
183
 
184
184
  except Exception as e:
185
185
  # Increment error counter
186
186
  self.meter.GlobalMetrics.error_invocations.add(1, {'function': span_name, 'error': type(e).__name__})
187
+
188
+ # Log error with context
189
+ self.logger.logger.error(f"Lambda execution failed: {e}", exc_info=True)
187
190
  raise
188
191
 
189
192
  finally:
193
+ # Record duration
194
+ duration = (datetime.now() - start_func).total_seconds() * 1000
195
+ self.meter.GlobalMetrics.duration.record(duration, {'function': span_name})
196
+
190
197
  if auto_flush:
191
- self.logger.logger.info(f"[OTEL] Lambda handler '{span_name}' completed, flushing telemetry...")
198
+ self.logger.logger.info(f"[OTEL] Lambda handler '{span_name}' completed in {duration:.2f}ms, flushing telemetry...")
192
199
  self.force_flush(start_datetime=start_func)
193
200
 
194
201
  return wrapper
195
202
  return decorator
196
203
 
204
+ def _process_lambda_result(self, result, span_context, span_name):
205
+ """Helper method to process Lambda result and update span accordingly"""
206
+ if isinstance(result, dict):
207
+ if 'statusCode' in result:
208
+ span_context.set_attribute("http.status_code", result['statusCode'])
209
+ # Set span status based on HTTP status code
210
+ if result['statusCode'] >= 400:
211
+ span_context.set_status(Status(StatusCode.ERROR, f"HTTP {result['statusCode']}"))
212
+ else:
213
+ span_context.set_status(Status(StatusCode.OK))
214
+
215
+ # Add completion event
216
+ span_context.add_event("lambda.invocation.complete",
217
+ attributes={"success": result.get('statusCode', 200) < 400})
218
+ else:
219
+ span_context.set_status(Status(StatusCode.OK))
220
+ span_context.add_event("lambda.invocation.complete", attributes={"success": True})
221
+
222
+ # Increment success counter
223
+ self.meter.GlobalMetrics.successful_invocations.add(1, {'function': span_name})
224
+
197
225
  def aws_message_handler(self,
198
226
  name: Optional[str] = None,
199
227
  attributes: Optional[Dict[str, Any]] = None,
rebrandly_otel/traces.py CHANGED
@@ -11,7 +11,7 @@ from opentelemetry.sdk.trace.export import (
11
11
  SimpleSpanProcessor
12
12
  )
13
13
 
14
- from otel_utils import *
14
+ from .otel_utils import *
15
15
 
16
16
  class RebrandlyTracer:
17
17
  """Wrapper for OpenTelemetry tracing with Rebrandly-specific features."""
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: rebrandly_otel
3
- Version: 0.1.8
3
+ Version: 0.1.10
4
4
  Summary: Python OTEL wrapper by Rebrandly
5
5
  Home-page: https://github.com/rebrandly/rebrandly-otel-python
6
6
  Author: Antonio Romano
@@ -0,0 +1,11 @@
1
+ rebrandly_otel/__init__.py,sha256=AHcEKWq4KRafIF_x_Y8jiIQ5crNG1nbEwdnlGaEP6js,287
2
+ rebrandly_otel/logs.py,sha256=92jaxzI5hCHnKHu3lsSAa7K_SPHQgL46AlQUESsYNds,3724
3
+ rebrandly_otel/metrics.py,sha256=57jwrn8e1u66BOO7fcFrmtE3Rpt4VDixG9I78K-zrUU,8537
4
+ rebrandly_otel/otel_utils.py,sha256=uJmfz2NspSnTVJXGKoaLUl1CYb0ow6VHKjmg2d_rdwg,1704
5
+ rebrandly_otel/rebrandly_otel.py,sha256=KSzrGSdUgqXZO1C0RBrBLNcAh-9oR5wqSWLJc0-Itww,21626
6
+ rebrandly_otel/traces.py,sha256=EiZMWNerzAisn_2MEcE9u1zVkRlZZrbnY3PVzVWWOuI,7048
7
+ rebrandly_otel-0.1.10.dist-info/licenses/LICENSE,sha256=KMXHvTwP62S2q-SG7CFfMU_09rUwxiqlM0izaYGdcgY,1103
8
+ rebrandly_otel-0.1.10.dist-info/METADATA,sha256=27eO_Dw6gLu-4FLXTW9rMj7zVmpImBHwKhAUjebmDWw,9628
9
+ rebrandly_otel-0.1.10.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
10
+ rebrandly_otel-0.1.10.dist-info/top_level.txt,sha256=26PSC1gjVUl8tTH5QfKbFevjVV4E2yojoukEfiTScvM,15
11
+ rebrandly_otel-0.1.10.dist-info/RECORD,,
@@ -1,11 +0,0 @@
1
- rebrandly_otel/__init__.py,sha256=AHcEKWq4KRafIF_x_Y8jiIQ5crNG1nbEwdnlGaEP6js,287
2
- rebrandly_otel/logs.py,sha256=kbJ5b352QgOihRyLe6bPW7P8IB5AnLoqSsCjL99sGYo,3723
3
- rebrandly_otel/metrics.py,sha256=AoVUn4v_PTABhylgOqNZH2cGBRnjDaCnb_4da9u27x4,8536
4
- rebrandly_otel/otel_utils.py,sha256=uJmfz2NspSnTVJXGKoaLUl1CYb0ow6VHKjmg2d_rdwg,1704
5
- rebrandly_otel/rebrandly_otel.py,sha256=SfqIU1spIt0UNhNwt7JKR3kG2--xTjZe5E26iqJsGV4,19816
6
- rebrandly_otel/traces.py,sha256=ShIer1SXzVHLfdKPrpfzoKF0DQ_n4EtJYI525JnuuMw,7047
7
- rebrandly_otel-0.1.8.dist-info/licenses/LICENSE,sha256=KMXHvTwP62S2q-SG7CFfMU_09rUwxiqlM0izaYGdcgY,1103
8
- rebrandly_otel-0.1.8.dist-info/METADATA,sha256=jiA_WVy9_OGH7CNYOZcrs19BH-wcsloO4H4KVy7ZID8,9627
9
- rebrandly_otel-0.1.8.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
10
- rebrandly_otel-0.1.8.dist-info/top_level.txt,sha256=26PSC1gjVUl8tTH5QfKbFevjVV4E2yojoukEfiTScvM,15
11
- rebrandly_otel-0.1.8.dist-info/RECORD,,