rebrandly-otel 0.1.18__py3-none-any.whl → 0.1.19__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
@@ -1,6 +1,7 @@
1
1
  # logs.py
2
2
  """Logging implementation for Rebrandly OTEL SDK."""
3
3
  import logging
4
+ import sys
4
5
  from typing import Optional
5
6
  from opentelemetry.sdk._logs import LoggerProvider, LoggingHandler
6
7
  from opentelemetry.sdk._logs.export import (
@@ -34,12 +35,15 @@ class RebrandlyLogger:
34
35
  self._provider.add_log_record_processor(SimpleLogRecordProcessor(console_exporter))
35
36
 
36
37
  # Add OTLP exporter if configured
37
- if get_otlp_endpoint():
38
- otlp_exporter = OTLPLogExporter(endpoint=get_otlp_endpoint())
38
+ otel_endpoint = get_otlp_endpoint()
39
+ if otel_endpoint:
40
+ otlp_exporter = OTLPLogExporter(
41
+ timeout=5,
42
+ endpoint=otel_endpoint
43
+ )
39
44
  batch_processor = BatchLogRecordProcessor(otlp_exporter, export_timeout_millis=get_millis_batch_time())
40
45
  self._provider.add_log_record_processor(batch_processor)
41
46
 
42
- # Set as global provider
43
47
  set_logger_provider(self._provider)
44
48
 
45
49
  # Configure standard logging
rebrandly_otel/metrics.py CHANGED
@@ -78,8 +78,12 @@ class RebrandlyMeter:
78
78
  readers.append(console_reader)
79
79
 
80
80
  # Add OTLP exporter if configured
81
- if get_otlp_endpoint() is not None:
82
- otlp_exporter = OTLPMetricExporter(endpoint=get_otlp_endpoint())
81
+ otel_endpoint = get_otlp_endpoint()
82
+ if otel_endpoint is not None:
83
+ otlp_exporter = OTLPMetricExporter(
84
+ endpoint=otel_endpoint,
85
+ timeout=5
86
+ )
83
87
  otlp_reader = PeriodicExportingMetricReader(otlp_exporter, export_interval_millis=get_millis_batch_time())
84
88
  readers.append(otlp_reader)
85
89
 
@@ -3,6 +3,7 @@
3
3
 
4
4
  import os
5
5
  import sys
6
+ import grpc
6
7
 
7
8
  from opentelemetry.sdk.resources import Resource
8
9
  from opentelemetry.semconv.attributes import service_attributes
@@ -33,8 +34,9 @@ def get_package_version():
33
34
  try:
34
35
  from importlib_metadata import version, PackageNotFoundError
35
36
  return version('rebrandly_otel')
36
- except:
37
- return '?.0.1'
37
+ except Exception as e:
38
+ print(f"[OTEL Utils] Warning: Could not get package version: {e}")
39
+ return '0.1.0'
38
40
 
39
41
 
40
42
  def get_service_name(service_name: str = None) -> str:
@@ -49,10 +51,31 @@ def get_service_version(service_version: str = None) -> str:
49
51
  return service_version
50
52
 
51
53
 
52
- def get_otlp_endpoint(otlp_endpoint: str = None) -> str:
53
- if otlp_endpoint is None:
54
- return os.environ.get('OTEL_EXPORTER_OTLP_ENDPOINT', None)
55
- return otlp_endpoint
54
+ def get_otlp_endpoint(otlp_endpoint: str = None) -> str | None:
55
+ endpoint = otlp_endpoint or os.environ.get('OTEL_EXPORTER_OTLP_ENDPOINT', None)
56
+
57
+ if endpoint is not None:
58
+ try:
59
+ from urllib.parse import urlparse
60
+
61
+ # Parse the endpoint
62
+ parsed = urlparse(endpoint if '://' in endpoint else f'http://{endpoint}')
63
+ host = parsed.hostname
64
+ port = parsed.port
65
+
66
+ # Test gRPC connection
67
+ channel = grpc.insecure_channel(f'{host}:{port}')
68
+ try:
69
+ # Wait for the channel to be ready
70
+ grpc.channel_ready_future(channel).result(timeout=3)
71
+ return endpoint
72
+ finally:
73
+ channel.close()
74
+
75
+ except Exception as e:
76
+ print(f"[OTEL] Failed to connect to OTLP endpoint {endpoint}: {e}")
77
+ return None
78
+ return endpoint
56
79
 
57
80
  def is_otel_debug() -> bool:
58
81
  return os.environ.get('OTEL_DEBUG', 'false').lower() == 'true'
@@ -61,5 +84,6 @@ def is_otel_debug() -> bool:
61
84
  def get_millis_batch_time():
62
85
  try:
63
86
  return int(os.environ.get('BATCH_EXPORT_TIME_MILLIS', 100))
64
- except:
87
+ except Exception as e:
88
+ print(f"[OTEL Utils] Warning: Invalid BATCH_EXPORT_TIME_MILLIS value, using default 5000ms: {e}")
65
89
  return 5000
@@ -260,7 +260,7 @@ class RebrandlyOTEL:
260
260
  try:
261
261
  # Create span and execute function
262
262
  span_function = self.span
263
- if record is not None and ('MessageAttributes' in record or 'messageAttributes' in record):
263
+ if record is not None and (('MessageAttributes' in record or 'messageAttributes' in record) or ('Sns' in record and 'MessageAttributes' in record['Sns'])):
264
264
  span_function = self.aws_message_span
265
265
 
266
266
  with span_function(span_name, message=record, attributes=span_attributes, kind=kind) as span_context:
@@ -370,6 +370,7 @@ class RebrandlyOTEL:
370
370
  time.sleep(0.1)
371
371
 
372
372
  except Exception as e:
373
+ print(f"[Rebrandly OTEL] Error during force flush: {e}")
373
374
  success = False
374
375
 
375
376
  return success
rebrandly_otel/traces.py CHANGED
@@ -32,8 +32,12 @@ class RebrandlyTracer:
32
32
  self._provider.add_span_processor(SimpleSpanProcessor(console_exporter))
33
33
 
34
34
  # Add OTLP exporter if configured
35
- if get_otlp_endpoint() is not None:
36
- otlp_exporter = OTLPSpanExporter(endpoint=get_otlp_endpoint())
35
+ otel_endpoint = get_otlp_endpoint()
36
+ if otel_endpoint is not None:
37
+ otlp_exporter = OTLPSpanExporter(
38
+ endpoint=otel_endpoint,
39
+ timeout=5
40
+ )
37
41
 
38
42
  # Use batch processor for production
39
43
  batch_processor = BatchSpanProcessor(otlp_exporter, export_timeout_millis=get_millis_batch_time())
@@ -139,14 +143,14 @@ class RebrandlyTracer:
139
143
  if target_span and hasattr(target_span, 'record_exception'):
140
144
  if exception is not None:
141
145
  target_span.record_exception(exception)
142
- target_span.set_status(trace.Status(trace.StatusCode.ERROR, str(exception)), description=msg)
146
+ target_span.set_status(trace.Status(trace.StatusCode.ERROR, str(exception)))
143
147
 
144
148
 
145
149
  def record_span_success(self, span: Optional[Span] = None, msg: Optional[str] = None):
146
- """Record an exception on a span."""
150
+ """Record success on a span."""
147
151
  target_span = span or self.get_current_span()
148
- if target_span and hasattr(target_span, 'record_exception'):
149
- target_span.set_status(trace.Status(trace.StatusCode.OK), description=msg)
152
+ if target_span and hasattr(target_span, 'set_status'):
153
+ target_span.set_status(trace.Status(trace.StatusCode.OK))
150
154
 
151
155
 
152
156
  def add_event(self, name: str, attributes: Optional[Dict[str, Any]] = None, span: Optional[Span] = None):
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: rebrandly_otel
3
- Version: 0.1.18
3
+ Version: 0.1.19
4
4
  Summary: Python OTEL wrapper by Rebrandly
5
5
  Home-page: https://github.com/rebrandly/rebrandly-otel-python
6
6
  Author: Antonio Romano
@@ -360,6 +360,93 @@ if __name__ == '__main__':
360
360
  app.run(debug=True)
361
361
  ```
362
362
 
363
+ ###
364
+ FastAPI
365
+
366
+ ```python
367
+
368
+ # main_fastapi.py
369
+ from fastapi import FastAPI, HTTPException, Depends
370
+ from contextlib import asynccontextmanager
371
+ from src.rebrandly_otel import otel, logger, force_flush
372
+ from src.fastapi_support import setup_fastapi, get_current_span
373
+ from datetime import datetime
374
+ from typing import Optional
375
+ import uvicorn
376
+
377
+ @asynccontextmanager
378
+ async def lifespan(app: FastAPI):
379
+ # Startup
380
+ logger.info("FastAPI application starting up")
381
+ yield
382
+ # Shutdown
383
+ logger.info("FastAPI application shutting down")
384
+ force_flush()
385
+
386
+ app = FastAPI(title="FastAPI OTEL Example", lifespan=lifespan)
387
+
388
+ # Setup FastAPI with OTEL
389
+ setup_fastapi(otel, app)
390
+
391
+ @app.get("/health")
392
+ async def health():
393
+ """Health check endpoint."""
394
+ logger.info("Health check requested")
395
+ return {"status": "healthy"}
396
+
397
+ @app.post("/process")
398
+ @app.get("/process")
399
+ async def process(span = Depends(get_current_span)):
400
+ """Process endpoint with custom span."""
401
+ with otel.span("process_request"):
402
+ logger.info("Processing request")
403
+
404
+ # You can also use the injected span directly
405
+ if span:
406
+ span.add_event("custom_processing_event", {
407
+ "timestamp": datetime.now().isoformat()
408
+ })
409
+
410
+ # Simulate some processing
411
+ result = {
412
+ "processed": True,
413
+ "timestamp": datetime.now().isoformat()
414
+ }
415
+
416
+ logger.info(f"Returning result: {result}")
417
+ return result
418
+
419
+ @app.get("/error")
420
+ async def error():
421
+ """Endpoint that raises an error."""
422
+ logger.error("Error endpoint called")
423
+ raise HTTPException(status_code=400, detail="Simulated error")
424
+
425
+ @app.get("/exception")
426
+ async def exception():
427
+ """Endpoint that raises an unhandled exception."""
428
+ logger.error("Exception endpoint called")
429
+ raise ValueError("Simulated unhandled exception")
430
+
431
+ @app.get("/items/{item_id}")
432
+ async def get_item(item_id: int, q: Optional[str] = None):
433
+ """Example endpoint with path and query parameters."""
434
+ with otel.span("fetch_item", attributes={"item_id": item_id, "query": q}):
435
+ logger.info(f"Fetching item {item_id} with query: {q}")
436
+
437
+ if item_id == 999:
438
+ raise HTTPException(status_code=404, detail="Item not found")
439
+
440
+ return {
441
+ "item_id": item_id,
442
+ "name": f"Item {item_id}",
443
+ "query": q
444
+ }
445
+
446
+ if __name__ == "__main__":
447
+ uvicorn.run(app, host="0.0.0.0", port=8000)
448
+ ```
449
+
363
450
  ### More examples
364
451
  You can find More examples [here](examples)
365
452
 
@@ -0,0 +1,13 @@
1
+ rebrandly_otel/__init__.py,sha256=tkZQJo5hR4FJ4dIRc-3b_YGxGo-uq-DsiSz8shdac-k,397
2
+ rebrandly_otel/fastapi_support.py,sha256=RuBBZJuzr3osBDrkHZ0oQPV70pmvnqxTfBBDVFBFQlo,8019
3
+ rebrandly_otel/flask_support.py,sha256=cUVMGTjN6N8xZD4Zyng2LRWhNj62C5nmTH91SnYBp2A,6072
4
+ rebrandly_otel/logs.py,sha256=5byeN-cDmBRpeZDw9IBz_vuiJm3wsGEbcAk5pwYHNAU,3791
5
+ rebrandly_otel/metrics.py,sha256=8aAqdr3SAcX_rVivTl_aHeD_BRByt-Qnfij_51Y7Fn0,7561
6
+ rebrandly_otel/otel_utils.py,sha256=ej6ayM1e9muHx1RNaEBZJTBIL_G0QAtDkqkS1VsoTyo,3026
7
+ rebrandly_otel/rebrandly_otel.py,sha256=hyNMFQzjZdP6oaXd0x1VKSKZg4-IuCtO6XeAiRZc7oo,21299
8
+ rebrandly_otel/traces.py,sha256=JY_3RWbzpUxzEx3GqTVgggsyA2DB4oR-zDftIFFJha4,7174
9
+ rebrandly_otel-0.1.19.dist-info/licenses/LICENSE,sha256=KMXHvTwP62S2q-SG7CFfMU_09rUwxiqlM0izaYGdcgY,1103
10
+ rebrandly_otel-0.1.19.dist-info/METADATA,sha256=DUACwLo6mJSEjir0pfY8kszp-G36JDnz5lh3uivRECg,12854
11
+ rebrandly_otel-0.1.19.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
12
+ rebrandly_otel-0.1.19.dist-info/top_level.txt,sha256=26PSC1gjVUl8tTH5QfKbFevjVV4E2yojoukEfiTScvM,15
13
+ rebrandly_otel-0.1.19.dist-info/RECORD,,
@@ -1,13 +0,0 @@
1
- rebrandly_otel/__init__.py,sha256=tkZQJo5hR4FJ4dIRc-3b_YGxGo-uq-DsiSz8shdac-k,397
2
- rebrandly_otel/fastapi_support.py,sha256=RuBBZJuzr3osBDrkHZ0oQPV70pmvnqxTfBBDVFBFQlo,8019
3
- rebrandly_otel/flask_support.py,sha256=cUVMGTjN6N8xZD4Zyng2LRWhNj62C5nmTH91SnYBp2A,6072
4
- rebrandly_otel/logs.py,sha256=92jaxzI5hCHnKHu3lsSAa7K_SPHQgL46AlQUESsYNds,3724
5
- rebrandly_otel/metrics.py,sha256=8Mgz_VcgsGQaBeYH2y6FtLGSqMqTwa2ilAa1pbYYymU,7472
6
- rebrandly_otel/otel_utils.py,sha256=tKelaETEeZxxvddKDpY8ESsGS77CcBbQku4oQjmiJx0,2078
7
- rebrandly_otel/rebrandly_otel.py,sha256=Es6ZQC2hr6qJ_M4Y-7nUvcAnGADj6-ofKn8hKFw7P1k,21166
8
- rebrandly_otel/traces.py,sha256=v582WtJv3t4Bn92vlDyZouibHtgWNxdRo_XmQCmSOEA,7126
9
- rebrandly_otel-0.1.18.dist-info/licenses/LICENSE,sha256=KMXHvTwP62S2q-SG7CFfMU_09rUwxiqlM0izaYGdcgY,1103
10
- rebrandly_otel-0.1.18.dist-info/METADATA,sha256=CyoVBpLByY8eqh5C7UTmKTBH62thbZww1GxPjYKSV6Y,10410
11
- rebrandly_otel-0.1.18.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
12
- rebrandly_otel-0.1.18.dist-info/top_level.txt,sha256=26PSC1gjVUl8tTH5QfKbFevjVV4E2yojoukEfiTScvM,15
13
- rebrandly_otel-0.1.18.dist-info/RECORD,,