rebrandly-otel 0.1.1__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.

@@ -0,0 +1,327 @@
1
+ Metadata-Version: 2.4
2
+ Name: rebrandly_otel
3
+ Version: 0.1.1
4
+ Summary: Python OTEL wrapper by Rebrandly
5
+ Home-page: https://github.com/pypa/sampleproject
6
+ Author: Antonio Romano
7
+ Author-email: antobio@rebrandly.com
8
+ Classifier: Programming Language :: Python :: 3
9
+ Classifier: License :: OSI Approved :: MIT License
10
+ Classifier: Operating System :: OS Independent
11
+ Description-Content-Type: text/markdown
12
+ License-File: LICENSE
13
+ Dynamic: author
14
+ Dynamic: author-email
15
+ Dynamic: classifier
16
+ Dynamic: description
17
+ Dynamic: description-content-type
18
+ Dynamic: home-page
19
+ Dynamic: license-file
20
+ Dynamic: summary
21
+
22
+ # Rebrandly OpenTelemetry SDK for Python
23
+
24
+ A comprehensive OpenTelemetry instrumentation SDK designed specifically for Rebrandly services, with built-in support for AWS Lambda functions and message processing.
25
+
26
+ ## Overview
27
+
28
+ The Rebrandly OpenTelemetry SDK provides a unified interface for distributed tracing, metrics collection, and structured logging across Python applications. It offers automatic instrumentation for AWS Lambda functions, simplified span management, and seamless integration with OTLP-compatible backends.
29
+
30
+ ## Installation
31
+
32
+ ```bash
33
+ pip install rebrandly-otel-sdk
34
+ ```
35
+
36
+ ### Dependencies
37
+
38
+ - `opentelemetry-api`
39
+ - `opentelemetry-sdk`
40
+ - `opentelemetry-exporter-otlp-proto-grpc`
41
+ - `opentelemetry-semantic-conventions`
42
+ - `psutil` (for system metrics)
43
+
44
+ ## Configuration
45
+
46
+ The SDK is configured through environment variables:
47
+
48
+ | Variable | Description | Default |
49
+ |------------------------------------|-------------|---------|
50
+ | `OTEL_SERVICE_NAME` | Service identifier | `default-service-python` |
51
+ | `OTEL_SERVICE_VERSION` | Service version | `1.0.0` |
52
+ | `OTEL_EXPORTER_OTLP_ENDPOINT` | OTLP collector endpoint | `None` |
53
+ | `OTEL_DEBUG` | Enable console debugging | `false` |
54
+ | `BATCH_EXPORT_TIME_MILLIS` | Batch export interval | `100` |
55
+ | `ENV` or `ENVIRONMENT` or `NODE_ENV` | Deployment environment | `local` |
56
+
57
+ ## Core Components
58
+
59
+ ### RebrandlyOTEL Class
60
+
61
+ The main entry point for all telemetry operations. Implements a singleton pattern to ensure consistent instrumentation across your application.
62
+
63
+ #### Properties
64
+
65
+ - **`tracer`**: Returns the `RebrandlyTracer` instance for distributed tracing
66
+ - **`meter`**: Returns the `RebrandlyMeter` instance for metrics collection
67
+ - **`logger`**: Returns the configured Python logger with OpenTelemetry integration
68
+
69
+ #### Initialization
70
+
71
+ The SDK auto-initializes as soon as you embed it.
72
+
73
+ ### Key Methods
74
+
75
+ #### `span(name, attributes=None, kind=SpanKind.INTERNAL, message=None)`
76
+
77
+ Context manager for creating traced spans with automatic error handling and status management.
78
+
79
+ #### `lambda_handler(name=None, attributes=None, kind=SpanKind.CONSUMER, auto_flush=True, skip_aws_link=True)`
80
+
81
+ Decorator for AWS Lambda functions with automatic instrumentation, metrics collection, and telemetry flushing.
82
+
83
+ #### `aws_message_handler(name=None, attributes=None, kind=SpanKind.CONSUMER, auto_flush=True)`
84
+
85
+ Decorator for processing individual AWS messages (SQS/SNS) with context propagation.
86
+
87
+ #### `aws_message_span(name, message=None, attributes=None, kind=SpanKind.CONSUMER)`
88
+
89
+ Context manager for creating spans from AWS messages with automatic context extraction.
90
+
91
+ #### `force_flush(start_datetime=None, timeout_millis=1000)`
92
+
93
+ Forces all pending telemetry data to be exported. Critical for serverless environments.
94
+
95
+ #### `shutdown()`
96
+
97
+ Gracefully shuts down all OpenTelemetry components.
98
+
99
+ ## Built-in Metrics
100
+
101
+ The SDK automatically registers and tracks the following metrics:
102
+
103
+ ### Standard Metrics
104
+
105
+ - **`invocations`** (Counter): Total number of function invocations
106
+ - **`successful_invocations`** (Counter): Number of successful completions
107
+ - **`error_invocations`** (Counter): Number of failed invocations
108
+ - **`duration`** (Histogram): Execution duration in milliseconds
109
+ - **`cpu_usage_percentage`** (Gauge): CPU utilization percentage
110
+ - **`memory_usage_bytes`** (Gauge): Memory usage in bytes
111
+
112
+ ### Global Metrics Access
113
+
114
+ ```python
115
+ from rebrandly_otel import meter
116
+
117
+ # Access pre-configured metrics
118
+ meter.GlobalMetrics.invocations.add(1, {'function': 'my_function'})
119
+ meter.GlobalMetrics.duration.record(150.5, {'source': 'api'})
120
+ ```
121
+
122
+ ## Tracing Features
123
+
124
+ ### Automatic Context Propagation
125
+
126
+ The SDK automatically extracts and propagates trace context from:
127
+ - AWS SQS message attributes
128
+ - AWS SNS message attributes
129
+ - HTTP headers
130
+ - Custom carriers
131
+
132
+ ### Span Attributes
133
+
134
+ Lambda spans automatically include:
135
+ - `faas.trigger`: Detected trigger type (sqs, sns, api_gateway, etc.)
136
+ - `faas.execution`: AWS request ID
137
+ - `faas.id`: Function ARN
138
+ - `cloud.provider`: Always "aws" for Lambda
139
+ - `cloud.platform`: Always "aws_lambda" for Lambda
140
+
141
+ ### Exception Handling
142
+
143
+ Spans automatically capture exceptions with:
144
+ - Full exception details and stack traces
145
+ - Automatic status code setting
146
+ - Exception events in the span timeline
147
+
148
+ ## Logging Integration
149
+
150
+ The SDK integrates with Python's standard logging module:
151
+
152
+ ```python
153
+ from rebrandly_otel import logger
154
+
155
+ # Use as a standard Python logger
156
+ logger.info("Processing started", extra={"request_id": "123"})
157
+ logger.error("Processing failed", exc_info=True)
158
+ ```
159
+
160
+ Features:
161
+ - Automatic trace context injection
162
+ - Structured logging support
163
+ - Console and OTLP export
164
+ - Log level configuration via environment
165
+
166
+ ## AWS Lambda Support
167
+
168
+ ### Trigger Detection
169
+
170
+ Automatically detects and labels Lambda triggers:
171
+ - API Gateway (v1 and v2)
172
+ - SQS
173
+ - SNS
174
+ - S3
175
+ - Kinesis
176
+ - DynamoDB
177
+ - EventBridge
178
+ - Batch
179
+
180
+ ### Automatic Metrics
181
+
182
+ For Lambda functions, the SDK automatically captures:
183
+ - Function duration
184
+ - Memory usage
185
+ - CPU utilization
186
+ - Invocation counts by status
187
+
188
+ ### Context Extraction
189
+
190
+ Automatically extracts trace context from:
191
+ - SQS MessageAttributes
192
+ - SNS MessageAttributes (including nested format)
193
+ - Custom message attributes
194
+
195
+ ## Performance Considerations
196
+
197
+ ### Batch Processing
198
+
199
+ - Configurable batch sizes and intervals
200
+ - Automatic batching for traces, metrics, and logs
201
+ - Optimized for high-throughput scenarios
202
+
203
+ ### Lambda Optimization
204
+
205
+ - Automatic flushing before function freeze
206
+ - Minimal cold start impact
207
+ - Efficient memory usage
208
+ - Configurable timeout handling
209
+
210
+ ## Export Formats
211
+
212
+ ### Supported Exporters
213
+
214
+ - **OTLP/gRPC**: Primary export format for production
215
+ - **Console**: Available for local development and debugging
216
+
217
+ ## Thread Safety
218
+
219
+ All components are thread-safe and can be used in multi-threaded applications:
220
+ - Singleton pattern ensures single initialization
221
+ - Thread-safe metric recording
222
+ - Concurrent span creation support
223
+
224
+ ## Resource Attributes
225
+
226
+ Automatically includes:
227
+ - Service name and version
228
+ - Python runtime version
229
+ - Deployment environment
230
+ - Custom resource attributes via environment
231
+
232
+ ## Error Handling
233
+
234
+ - Graceful degradation when OTLP endpoint unavailable
235
+ - Non-blocking telemetry operations
236
+ - Automatic retry with exponential backoff
237
+ - Comprehensive error logging
238
+
239
+ ## Compatibility
240
+
241
+ - Python 3.7+
242
+ - AWS Lambda runtime support
243
+ - Compatible with OpenTelemetry Collector
244
+ - Works with any OTLP-compatible backend
245
+
246
+ ## Examples
247
+
248
+ ### Lambda - Send SNS / SQS message
249
+ ```python
250
+ import os
251
+ import json
252
+ import boto3
253
+ from rebrandly_otel import otel, lambda_handler, logger
254
+
255
+ sqs = boto3.client('sqs')
256
+ QUEUE_URL = os.environ.get('SQS_URL')
257
+
258
+ @lambda_handler("sqs_sender")
259
+ def handler(event, context):
260
+ logger.info("Starting SQS message send")
261
+
262
+ # Get trace context for propagation
263
+ trace_attrs = otel.tracer.get_attributes_for_aws_from_context()
264
+
265
+ # Send message with trace context
266
+ response = sqs.send_message(
267
+ QueueUrl=QUEUE_URL,
268
+ MessageBody=json.dumps({"data": "test message"}),
269
+ MessageAttributes=trace_attrs
270
+ )
271
+
272
+ logger.info(f"Sent SQS message: {response['MessageId']}")
273
+
274
+ return {
275
+ 'statusCode': 200,
276
+ 'body': json.dumps({'messageId': response['MessageId']})
277
+ }
278
+ ```
279
+
280
+ ### Lambda Receive SQS message
281
+ ```python
282
+ import json
283
+ from rebrandly_otel import lambda_handler, logger, aws_message_span
284
+
285
+ @lambda_handler(name="sqs_receiver")
286
+ def handler(event, context):
287
+ for record in event['Records']:
288
+ # Process each message with trace context
289
+ process_message(record)
290
+
291
+ def process_message(record):
292
+ with aws_message_span("process_message_sqs_receiver", message=record) as s:
293
+ logger.info(f"Processing message: {record['messageId']}")
294
+
295
+ # Parse message body
296
+ body = json.loads(record['body'])
297
+ logger.info(f"Message data: {body}")
298
+ ```
299
+
300
+ ### Lambda Receive SNS message (record specific event)
301
+ ```python
302
+ import json
303
+ from rebrandly_otel import lambda_handler, logger, aws_message_span
304
+
305
+ @lambda_handler(name="sns_receiver")
306
+ def handler(event, context):
307
+ for record in event['Records']:
308
+ # Process each message with trace context
309
+ process_message(record)
310
+
311
+ def process_message(record):
312
+ message = json.loads(record['Sns']['Message'])
313
+ if message['event'] == 'whitelisted-event':
314
+ with aws_message_span("process_message_sns_receiver", message=record) as s:
315
+ logger.info(f"Processing message: {record['messageId']}")
316
+
317
+ # Parse message body
318
+ body = json.loads(record['body'])
319
+ logger.info(f"Message data: {body}")
320
+ ```
321
+
322
+ ### More examples
323
+ You can find More examples [here](examples)
324
+
325
+ ## License
326
+
327
+ Rebrandly Python SDK is released under the MIT License.
@@ -0,0 +1,11 @@
1
+ rebrandly_otel-0.1.1.dist-info/licenses/LICENSE,sha256=KMXHvTwP62S2q-SG7CFfMU_09rUwxiqlM0izaYGdcgY,1103
2
+ src/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
3
+ src/logs.py,sha256=eClyZfmlE85Y8S0ZqrJoilf6SvwkT1p6aUfX57IBy-s,3727
4
+ src/metrics.py,sha256=TyVEAaWyKuPoQRMBpkYhT4SUx6GYtnyEuz6DQtEK93I,8540
5
+ src/otel_utils.py,sha256=uJmfz2NspSnTVJXGKoaLUl1CYb0ow6VHKjmg2d_rdwg,1704
6
+ src/rebrandly_otel.py,sha256=9QhKD37ZqVauikAxNUN8C4muXOJSg_mioFt--jwL9IU,19828
7
+ src/traces.py,sha256=O_9wEpsW8mBlJEwVQj9QQXKB8WHYPNigtiOEBX7xanQ,7051
8
+ rebrandly_otel-0.1.1.dist-info/METADATA,sha256=oSXPbAfvQywoWT99Cm2kxgf8ohbOR2G8h3yShAuK_bw,9398
9
+ rebrandly_otel-0.1.1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
10
+ rebrandly_otel-0.1.1.dist-info/top_level.txt,sha256=74rtVfumQlgAPzR5_2CgYN24MB0XARCg0t-gzk6gTrM,4
11
+ rebrandly_otel-0.1.1.dist-info/RECORD,,
@@ -0,0 +1,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (80.9.0)
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
5
+
@@ -0,0 +1,19 @@
1
+ Copyright (C) 2025 RadiateCapital Ltd (dba Rebrandly). (https://rebrandly.com)
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ of this software and associated documentation files (the "Software"), to deal
5
+ in the Software without restriction, including without limitation the rights
6
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ copies of the Software, and to permit persons to whom the Software is
8
+ furnished to do so, subject to the following conditions:
9
+
10
+ The above copyright notice and this permission notice shall be included in
11
+ all copies or substantial portions of the Software.
12
+
13
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
+ THE SOFTWARE.
@@ -0,0 +1 @@
1
+ src
src/__init__.py ADDED
File without changes
src/logs.py ADDED
@@ -0,0 +1,112 @@
1
+ # logs.py
2
+ """Logging implementation for Rebrandly OTEL SDK."""
3
+ import logging
4
+ from typing import Optional
5
+ from opentelemetry.sdk._logs import LoggerProvider, LoggingHandler
6
+ from opentelemetry.sdk._logs.export import (
7
+ BatchLogRecordProcessor,
8
+ ConsoleLogExporter,
9
+ SimpleLogRecordProcessor
10
+ )
11
+ from opentelemetry.exporter.otlp.proto.grpc._log_exporter import OTLPLogExporter
12
+ from opentelemetry._logs import set_logger_provider
13
+
14
+ from src.otel_utils import *
15
+
16
+
17
+ class RebrandlyLogger:
18
+ """Wrapper for OpenTelemetry logging with Rebrandly-specific features."""
19
+
20
+ def __init__(self):
21
+ self._logger: Optional[logging.Logger] = None
22
+ self._provider: Optional[LoggerProvider] = None
23
+ self._setup_logging()
24
+
25
+ def _setup_logging(self):
26
+ """Initialize logging with configured exporters."""
27
+
28
+ # Create provider with resource
29
+ self._provider = LoggerProvider(resource=create_resource())
30
+
31
+ # Add console exporter for local debugging
32
+ if is_otel_debug():
33
+ console_exporter = ConsoleLogExporter()
34
+ self._provider.add_log_record_processor(SimpleLogRecordProcessor(console_exporter))
35
+
36
+ # Add OTLP exporter if configured
37
+ if get_otlp_endpoint():
38
+ otlp_exporter = OTLPLogExporter(endpoint=get_otlp_endpoint())
39
+ batch_processor = BatchLogRecordProcessor(otlp_exporter, export_timeout_millis=get_millis_batch_time())
40
+ self._provider.add_log_record_processor(batch_processor)
41
+
42
+ # Set as global provider
43
+ set_logger_provider(self._provider)
44
+
45
+ # Configure standard logging
46
+ self._configure_standard_logging()
47
+
48
+ def _configure_standard_logging(self):
49
+ """Configure standard Python logging with OTEL handler."""
50
+ # Set up basic configuration
51
+ logging.basicConfig(
52
+ level=logging.INFO,
53
+ format="%(asctime)s - %(name)s - %(levelname)s - %(message)s",
54
+ stream=sys.stdout,
55
+ force=True
56
+ )
57
+
58
+ # Add OTEL handler
59
+ otel_handler = LoggingHandler(logger_provider=self._provider)
60
+ otel_handler.setLevel(logging.INFO)
61
+
62
+ # Get root logger
63
+ root_logger = logging.getLogger()
64
+ root_logger.addHandler(otel_handler)
65
+
66
+ # Create service-specific logger
67
+ self._logger = logging.getLogger(get_service_name())
68
+
69
+
70
+ @property
71
+ def logger(self) -> logging.Logger:
72
+ """Get the standard Python logger."""
73
+ if not self._logger:
74
+ self._logger = logging.getLogger(get_service_name())
75
+ return self._logger
76
+
77
+ def force_flush(self, timeout_millis: int = 5000) -> bool:
78
+ """
79
+ Force flush all pending logs.
80
+
81
+ Args:
82
+ timeout_millis: Maximum time to wait for flush in milliseconds
83
+
84
+ Returns:
85
+ True if flush succeeded, False otherwise
86
+ """
87
+ if not self._provider:
88
+ return True
89
+
90
+ try:
91
+ # Force flush the logger provider
92
+ success = self._provider.force_flush(timeout_millis)
93
+
94
+ # Also flush Python's logging handlers
95
+ if self._logger:
96
+ for handler in self._logger.handlers:
97
+ if hasattr(handler, 'flush'):
98
+ handler.flush()
99
+
100
+ return success
101
+ except Exception as e:
102
+ print(f"[Logger] Error during force flush: {e}")
103
+ return False
104
+
105
+ def shutdown(self):
106
+ """Shutdown the logger provider."""
107
+ if self._provider:
108
+ try:
109
+ self._provider.shutdown()
110
+ print("[Logger] Shutdown completed")
111
+ except Exception as e:
112
+ print(f"[Logger] Error during shutdown: {e}")