|
3 | 3 | import os |
4 | 4 |
|
5 | 5 | # Third-party |
6 | | -from opentelemetry import trace |
7 | | -from opentelemetry.trace import Status, StatusCode |
| 6 | +from applicationinsights import TelemetryClient |
| 7 | +from applicationinsights.channel import SynchronousSender, SynchronousQueue, TelemetryChannel |
8 | 8 |
|
9 | 9 | from dotenv import load_dotenv |
10 | 10 |
|
11 | 11 | load_dotenv() |
12 | 12 |
|
| 13 | +# Global telemetry client (initialized once) |
| 14 | +_telemetry_client = None |
| 15 | + |
| 16 | + |
| 17 | +def _get_telemetry_client(): |
| 18 | + """Get or create the Application Insights telemetry client.""" |
| 19 | + global _telemetry_client |
| 20 | + |
| 21 | + if _telemetry_client is None: |
| 22 | + connection_string = os.getenv("APPLICATIONINSIGHTS_CONNECTION_STRING") |
| 23 | + if connection_string: |
| 24 | + try: |
| 25 | + # Extract instrumentation key from connection string |
| 26 | + # Format: InstrumentationKey=xxx;IngestionEndpoint=https://... |
| 27 | + parts = dict(part.split('=', 1) for part in connection_string.split(';') if '=' in part) |
| 28 | + instrumentation_key = parts.get('InstrumentationKey') |
| 29 | + |
| 30 | + if instrumentation_key: |
| 31 | + # Create a synchronous channel for immediate sending |
| 32 | + sender = SynchronousSender() |
| 33 | + queue = SynchronousQueue(sender) |
| 34 | + channel = TelemetryChannel(None, queue) |
| 35 | + |
| 36 | + _telemetry_client = TelemetryClient(instrumentation_key, channel) |
| 37 | + logging.info("Application Insights TelemetryClient initialized successfully") |
| 38 | + else: |
| 39 | + logging.error("Could not extract InstrumentationKey from connection string") |
| 40 | + except Exception as e: |
| 41 | + logging.error(f"Failed to initialize TelemetryClient: {e}") |
| 42 | + |
| 43 | + return _telemetry_client |
| 44 | + |
13 | 45 |
|
14 | 46 | def track_event_if_configured(event_name: str, event_data: dict): |
15 | | - """Track a custom event using OpenTelemetry. |
| 47 | + """Track a custom event to Application Insights customEvents table. |
16 | 48 | |
17 | | - This creates a span with the event name and adds the event data as attributes. |
18 | | - The span will appear in Application Insights as a dependency with the event data. |
| 49 | + This uses the Application Insights SDK TelemetryClient which properly |
| 50 | + sends custom events to the customEvents table in Application Insights. |
19 | 51 | """ |
20 | 52 | instrumentation_key = os.getenv("APPLICATIONINSIGHTS_CONNECTION_STRING") |
21 | 53 | if instrumentation_key: |
22 | 54 | try: |
23 | | - tracer = trace.get_tracer(__name__) |
24 | | - with tracer.start_as_current_span(f"event:{event_name}") as span: |
25 | | - # Set span kind to internal for custom events |
26 | | - span.set_attribute("event.name", event_name) |
27 | | - span.set_attribute("event.type", "custom") |
28 | | - |
29 | | - # Add all event data as span attributes |
30 | | - for key, value in event_data.items(): |
31 | | - # Convert value to string to ensure it's serializable |
32 | | - span.set_attribute(f"event.{key}", str(value)) |
| 55 | + client = _get_telemetry_client() |
| 56 | + if client: |
| 57 | + # Convert all values to strings to ensure compatibility |
| 58 | + properties = {k: str(v) for k, v in event_data.items()} |
33 | 59 |
|
34 | | - # Add event to the span (appears in Application Insights) |
35 | | - span.add_event(event_name, attributes=event_data) |
36 | | - span.set_status(Status(StatusCode.OK)) |
| 60 | + # Track the custom event |
| 61 | + client.track_event(event_name, properties=properties) |
| 62 | + client.flush() # Ensure immediate sending |
37 | 63 |
|
38 | | - logging.debug(f"Tracked event: {event_name} with data: {event_data}") |
| 64 | + logging.debug(f"Tracked custom event: {event_name} with data: {event_data}") |
| 65 | + else: |
| 66 | + logging.warning("TelemetryClient not available, custom event not tracked") |
39 | 67 | except Exception as e: |
40 | 68 | logging.error(f"Failed to track event {event_name}: {e}") |
41 | 69 | else: |
|
0 commit comments