Skip to content

Commit df679f0

Browse files
committed
removing decorators and using auto_instrument_package Function wrapping
1 parent 4896471 commit df679f0

File tree

13 files changed

+527
-194
lines changed

13 files changed

+527
-194
lines changed

examples/run_all_traces.py

Lines changed: 61 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -29,13 +29,9 @@
2929
import pandas as pd
3030

3131
from src.telemetry import setup_telemetry
32-
from src.numerical.optimization import gradient_descent
33-
from src.algorithms.graph import graph_traversal, find_node_clusters, PathFinder, calculate_node_betweenness
34-
from src.algorithms.dynamic_programming import fibonacci, matrix_sum, matrix_chain_order, coin_change, knapsack
35-
from src.data_processing.dataframe import dataframe_filter, groupby_mean, dataframe_merge
36-
from src.statistics.descriptive import describe, correlation
32+
from src.telemetry.auto_instrumentation import auto_instrument_package
3733

38-
# Initialize OpenTelemetry with auto-instrumentation
34+
# Initialize OpenTelemetry with auto-instrumentation FIRST
3935
# Uses environment variables if set, otherwise defaults to console exporter
4036
print("=" * 80)
4137
print("Initializing OpenTelemetry with auto-instrumentation...")
@@ -51,13 +47,58 @@
5147
exporter_type = os.getenv("OTEL_TRACES_EXPORTER") or os.getenv("OTEL_EXPORTER_TYPE", "console")
5248
exporter_endpoint = os.getenv("OTEL_EXPORTER_OTLP_ENDPOINT", "http://localhost:4317")
5349

54-
setup_telemetry(
55-
service_name="optimize-me",
56-
service_version="0.1.0",
57-
exporter_type=exporter_type,
58-
exporter_endpoint=exporter_endpoint,
59-
use_auto_instrumentation=True, # Use auto-instrumentation (standard pattern)
50+
# Detect if running under opentelemetry-instrument
51+
# opentelemetry-instrument sets up its own TracerProvider, so we shouldn't replace it
52+
from opentelemetry import trace
53+
existing_provider = trace.get_tracer_provider()
54+
is_opentelemetry_instrument = (
55+
existing_provider is not None
56+
and not isinstance(existing_provider, trace.NoOpTracerProvider)
57+
and type(existing_provider).__name__ in ("ProxyTracerProvider", "TracerProvider")
58+
)
59+
60+
if is_opentelemetry_instrument:
61+
print("Detected opentelemetry-instrument - using existing OpenTelemetry setup")
62+
print(f"Exporter: {exporter_type}, Endpoint: {exporter_endpoint}")
63+
# Still call setup_telemetry to ensure console exporter is added if needed
64+
# setup_telemetry handles ProxyTracerProvider by creating a new TracerProvider
65+
# This ensures we have a console exporter configured for immediate output
66+
setup_telemetry(
67+
service_name="optimize-me",
68+
service_version="0.1.0",
69+
exporter_type=exporter_type, # Use console when OTEL_TRACES_EXPORTER=console
70+
exporter_endpoint=exporter_endpoint,
71+
use_auto_instrumentation=True,
72+
)
73+
if exporter_type == "console":
74+
print("✅ Console exporter configured - traces will appear below")
75+
else:
76+
# Call setup_telemetry to create TracerProvider and configure exporter
77+
setup_telemetry(
78+
service_name="optimize-me",
79+
service_version="0.1.0",
80+
exporter_type=exporter_type,
81+
exporter_endpoint=exporter_endpoint,
82+
use_auto_instrumentation=True, # Use auto-instrumentation (standard pattern)
83+
)
84+
85+
# Auto-instrument all custom functions in src package
86+
# This automatically traces all functions without requiring decorators
87+
# IMPORTANT: This must happen BEFORE importing the modules
88+
print("\nSetting up auto-instrumentation for custom functions...")
89+
auto_instrument_package(
90+
'src',
91+
include_private=False, # Don't instrument private functions (starting with _)
92+
exclude_modules=['src.tests', 'src.telemetry'] # Exclude test and telemetry modules
6093
)
94+
print("✅ Auto-instrumentation enabled - all functions will be traced automatically")
95+
96+
# NOW import modules - functions will be automatically wrapped
97+
from src.numerical.optimization import gradient_descent
98+
from src.algorithms.graph import graph_traversal, find_node_clusters, PathFinder, calculate_node_betweenness
99+
from src.algorithms.dynamic_programming import fibonacci, matrix_sum, matrix_chain_order, coin_change, knapsack
100+
from src.data_processing.dataframe import dataframe_filter, groupby_mean, dataframe_merge
101+
from src.statistics.descriptive import describe, correlation
61102

62103
print("\n" + "=" * 80)
63104
print("RUNNING ALL INSTRUMENTED FUNCTIONS")
@@ -202,11 +243,15 @@
202243
# Force flush spans to ensure they're exported (especially for console exporter)
203244
try:
204245
from opentelemetry import trace
246+
from opentelemetry.sdk.trace import TracerProvider
205247
provider = trace.get_tracer_provider()
206-
if hasattr(provider, "force_flush"):
207-
provider.force_flush()
208-
except Exception:
209-
pass
248+
if isinstance(provider, TracerProvider):
249+
if hasattr(provider, "force_flush"):
250+
provider.force_flush(timeout_millis=5000) # Wait up to 5 seconds
251+
print("\n✅ Spans flushed to exporter")
252+
except Exception as e:
253+
if os.getenv("OTEL_LOG_LEVEL", "").upper() == "DEBUG":
254+
print(f"\n⚠️ Could not flush spans: {e}")
210255

211256
print()
212257

src/algorithms/dynamic_programming.py

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,16 @@
11
from __future__ import annotations
22

3-
from src.telemetry.decorators import trace_function
43

5-
6-
@trace_function
74
def fibonacci(n):
85
if n <= 1:
96
return n
107
return fibonacci(n - 1) + fibonacci(n - 2)
118

129

13-
@trace_function
1410
def matrix_sum(matrix: list[list[int]]) -> list[int]:
1511
return [sum(matrix[i]) for i in range(len(matrix)) if sum(matrix[i]) > 0]
1612

1713

18-
@trace_function
1914
def matrix_chain_order(matrices: list[tuple[int, int]]) -> int:
2015
"""
2116
Find the minimum number of operations needed to multiply a chain of matrices.
@@ -47,7 +42,6 @@ def dp(i: int, j: int) -> int:
4742
return dp(0, n - 1)
4843

4944

50-
@trace_function
5145
def coin_change(coins: list[int], amount: int, index: int) -> int:
5246
if amount == 0:
5347
return 1
@@ -59,7 +53,6 @@ def coin_change(coins: list[int], amount: int, index: int) -> int:
5953
)
6054

6155

62-
@trace_function
6356
def knapsack(weights: list[int], values: list[int], capacity: int, n: int) -> int:
6457
if n == 0 or capacity == 0:
6558
return 0

src/algorithms/graph.py

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,7 @@
22

33
import networkx as nx
44

5-
from src.telemetry.decorators import trace_function
65

7-
8-
@trace_function
96
def graph_traversal(graph: dict[int, dict[int]], node: int) -> dict[int]:
107
visited = []
118

@@ -24,7 +21,6 @@ class PathFinder:
2421
def __init__(self, graph: dict[str, list[str]]):
2522
self.graph = graph
2623

27-
@trace_function
2824
def find_shortest_path(self, start: str, end: str) -> list[str]:
2925
if start not in self.graph or end not in self.graph:
3026
return []
@@ -106,7 +102,6 @@ def find_node_with_highest_degree(
106102
return max_degree_node
107103

108104

109-
@trace_function
110105
def find_node_clusters(nodes: list[dict], edges: list[dict]) -> list[list[dict]]:
111106
"""Find connected components (clusters) in the graph."""
112107
# Create node ID to node mapping for easy lookup
@@ -154,7 +149,6 @@ def find_node_clusters(nodes: list[dict], edges: list[dict]) -> list[list[dict]]
154149
return clusters
155150

156151

157-
@trace_function
158152
def calculate_node_betweenness(
159153
nodes: list[str], edges: list[dict[str, str]]
160154
) -> dict[str, float]:

src/data_processing/dataframe.py

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,7 @@
33
import numpy as np
44
import pandas as pd
55

6-
from src.telemetry.decorators import trace_function
76

8-
9-
@trace_function
107
def dataframe_filter(df: pd.DataFrame, column: str, value: Any) -> pd.DataFrame:
118
indices = []
129
for i in range(len(df)):
@@ -15,7 +12,6 @@ def dataframe_filter(df: pd.DataFrame, column: str, value: Any) -> pd.DataFrame:
1512
return df.iloc[indices].reset_index(drop=True)
1613

1714

18-
@trace_function
1915
def groupby_mean(df: pd.DataFrame, group_col: str, value_col: str) -> dict[Any, float]:
2016
sums = {}
2117
counts = {}
@@ -34,7 +30,6 @@ def groupby_mean(df: pd.DataFrame, group_col: str, value_col: str) -> dict[Any,
3430
return result
3531

3632

37-
@trace_function
3833
def dataframe_merge(
3934
left: pd.DataFrame, right: pd.DataFrame, left_on: str, right_on: str
4035
) -> pd.DataFrame:

src/numerical/optimization.py

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,6 @@
11
import numpy as np
22

3-
from src.telemetry.decorators import trace_function
43

5-
6-
@trace_function(span_name="gradient_descent", capture_args=["iterations", "learning_rate"])
74
def gradient_descent(
85
X: np.ndarray, y: np.ndarray, learning_rate: float = 0.01, iterations: int = 1000
96
) -> np.ndarray:

src/statistics/descriptive.py

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,7 @@
33
import numpy as np
44
import pandas as pd
55

6-
from src.telemetry.decorators import trace_function
76

8-
9-
@trace_function
107
def describe(series: pd.Series) -> dict[str, float]:
118
values = [v for v in series if not pd.isna(v)]
129
n = len(values)
@@ -44,7 +41,6 @@ def percentile(p):
4441
}
4542

4643

47-
@trace_function
4844
def correlation(df: pd.DataFrame) -> dict[Tuple[str, str], float]:
4945
numeric_columns = [
5046
col for col in df.columns if np.issubdtype(df[col].dtype, np.number)

0 commit comments

Comments
 (0)