Christian Kniep commited on
Commit
1ab5126
Β·
1 Parent(s): 5148b3d

disable tracing

Browse files
src/app.py CHANGED
@@ -139,11 +139,13 @@ def register_middleware(app):
139
  @app.before_request
140
  def before_request():
141
  """Start request timer and generate request ID, create tracing span."""
 
 
142
  g.start_time = time.time()
143
  g.request_id = request.headers.get("X-Request-ID", os.urandom(8).hex())
144
 
145
- # Skip tracing for health endpoint
146
- if request.path == "/health":
147
  return
148
 
149
  # Extract parent span context from headers if present
 
139
  @app.before_request
140
  def before_request():
141
  """Start request timer and generate request ID, create tracing span."""
142
+ from .utils.tracing import is_tracing_enabled
143
+
144
  g.start_time = time.time()
145
  g.request_id = request.headers.get("X-Request-ID", os.urandom(8).hex())
146
 
147
+ # Skip tracing if disabled or for health endpoint
148
+ if not is_tracing_enabled() or request.path == "/health":
149
  return
150
 
151
  # Extract parent span context from headers if present
src/routes/contacts.py CHANGED
@@ -38,15 +38,24 @@ def list_contacts():
38
  - search: Filter contacts by name (case-insensitive)
39
  - sort: Sort order (recent, alphabetical, oldest)
40
  """
 
 
41
  tracer = trace.get_tracer(__name__)
42
  user_id = session.get("user_id")
43
  search_query = request.args.get("search", "").strip()
44
  sort_order = request.args.get("sort", "recent")
45
 
46
- with tracer.start_as_current_span("list_contacts") as span:
 
 
 
47
  span.set_attribute("user_id", user_id)
48
  span.set_attribute("search_query", search_query)
49
  span.set_attribute("sort_order", sort_order)
 
 
 
 
50
 
51
  try:
52
  # Get all contacts for user
@@ -68,8 +77,9 @@ def list_contacts():
68
  contacts = sorted(contacts, key=lambda c: c.created_at)
69
  # Default "recent" is already sorted by last_interaction DESC
70
 
71
- span.set_attribute("contact_count", len(contacts))
72
- span.set_attribute("filtered", bool(search_query))
 
73
 
74
  return render_template(
75
  "contacts/list.html",
@@ -80,11 +90,15 @@ def list_contacts():
80
  )
81
 
82
  except Exception as e:
83
- span.set_attribute("error", True)
84
- span.add_event("error", {"message": str(e)})
 
85
  logger.error(f"Error loading contacts for user {user_id}: {e}")
86
  flash("Error loading contacts. Please try again.", "danger")
87
  return render_template("contacts/list.html", contacts=[], contact_count=0)
 
 
 
88
 
89
 
90
  @contacts_bp.route("/", methods=["POST"])
 
38
  - search: Filter contacts by name (case-insensitive)
39
  - sort: Sort order (recent, alphabetical, oldest)
40
  """
41
+ from ..utils.tracing import is_tracing_enabled
42
+
43
  tracer = trace.get_tracer(__name__)
44
  user_id = session.get("user_id")
45
  search_query = request.args.get("search", "").strip()
46
  sort_order = request.args.get("sort", "recent")
47
 
48
+ # Only create span if tracing is enabled
49
+ tracing_enabled = is_tracing_enabled()
50
+ if tracing_enabled:
51
+ span = tracer.start_span("list_contacts")
52
  span.set_attribute("user_id", user_id)
53
  span.set_attribute("search_query", search_query)
54
  span.set_attribute("sort_order", sort_order)
55
+ else:
56
+ span = None
57
+
58
+ try:
59
 
60
  try:
61
  # Get all contacts for user
 
77
  contacts = sorted(contacts, key=lambda c: c.created_at)
78
  # Default "recent" is already sorted by last_interaction DESC
79
 
80
+ if span:
81
+ span.set_attribute("contact_count", len(contacts))
82
+ span.set_attribute("filtered", bool(search_query))
83
 
84
  return render_template(
85
  "contacts/list.html",
 
90
  )
91
 
92
  except Exception as e:
93
+ if span:
94
+ span.set_attribute("error", True)
95
+ span.add_event("error", {"message": str(e)})
96
  logger.error(f"Error loading contacts for user {user_id}: {e}")
97
  flash("Error loading contacts. Please try again.", "danger")
98
  return render_template("contacts/list.html", contacts=[], contact_count=0)
99
+ finally:
100
+ if span:
101
+ span.end()
102
 
103
 
104
  @contacts_bp.route("/", methods=["POST"])
src/services/backend_client.py CHANGED
@@ -38,9 +38,11 @@ class BackendAPIClient:
38
  if self.bearer_token:
39
  headers["Authorization"] = f"Bearer {self.bearer_token}"
40
 
41
- # Inject trace context into headers automatically
42
  try:
43
- TraceContextTextMapPropagator().inject(headers)
 
 
44
  except Exception:
45
  # Don't fail request if tracing injection fails
46
  pass
 
38
  if self.bearer_token:
39
  headers["Authorization"] = f"Bearer {self.bearer_token}"
40
 
41
+ # Inject trace context into headers automatically (only if tracing enabled)
42
  try:
43
+ from ..utils.tracing import is_tracing_enabled
44
+ if is_tracing_enabled():
45
+ TraceContextTextMapPropagator().inject(headers)
46
  except Exception:
47
  # Don't fail request if tracing injection fails
48
  pass
src/services/storage_service.py CHANGED
@@ -399,11 +399,19 @@ def list_contact_sessions(
399
  List of ContactSession objects
400
  """
401
  from opentelemetry import trace
 
 
402
  tracer = trace.get_tracer(__name__)
403
 
404
- with tracer.start_as_current_span("storage.list_contact_sessions") as span:
 
 
405
  span.set_attribute("user_id", user_id)
406
  span.set_attribute("sort_by", sort_by)
 
 
 
 
407
 
408
  conn = get_db_connection()
409
  cursor = conn.cursor()
@@ -437,8 +445,12 @@ def list_contact_sessions(
437
  for row in rows
438
  ]
439
 
440
- span.set_attribute("result_count", len(contacts))
 
441
  return contacts
 
 
 
442
 
443
 
444
  def get_contact_session(session_id: str) -> Optional[ContactSession]:
 
399
  List of ContactSession objects
400
  """
401
  from opentelemetry import trace
402
+ from ..utils.tracing import is_tracing_enabled
403
+
404
  tracer = trace.get_tracer(__name__)
405
 
406
+ # Only create span if tracing is enabled
407
+ if is_tracing_enabled():
408
+ span = tracer.start_span("storage.list_contact_sessions")
409
  span.set_attribute("user_id", user_id)
410
  span.set_attribute("sort_by", sort_by)
411
+ else:
412
+ span = None
413
+
414
+ try:
415
 
416
  conn = get_db_connection()
417
  cursor = conn.cursor()
 
445
  for row in rows
446
  ]
447
 
448
+ if span:
449
+ span.set_attribute("result_count", len(contacts))
450
  return contacts
451
+ finally:
452
+ if span:
453
+ span.end()
454
 
455
 
456
  def get_contact_session(session_id: str) -> Optional[ContactSession]:
src/utils/__pycache__/tracing.cpython-313.pyc ADDED
Binary file (3.78 kB). View file
 
src/utils/tracing.py CHANGED
@@ -18,6 +18,16 @@ from opentelemetry.instrumentation.requests import RequestsInstrumentor
18
  logger = logging.getLogger(__name__)
19
 
20
 
 
 
 
 
 
 
 
 
 
 
21
  def init_tracer(service_name: str) -> trace.Tracer:
22
  """
23
  Initialize OpenTelemetry tracer with OTLP HTTP exporter for Jaeger.
@@ -25,12 +35,21 @@ def init_tracer(service_name: str) -> trace.Tracer:
25
  Uses HTTP protocol like the Go API (instead of unreliable UDP).
26
  Jaeger >= 1.35 supports OTLP natively on port 4318.
27
 
 
 
28
  Args:
29
  service_name: Name of the service for tracing
30
 
31
  Returns:
32
- Configured tracer instance
33
  """
 
 
 
 
 
 
 
34
  # Jaeger OTLP HTTP endpoint (port 4318)
35
  otlp_endpoint = os.getenv("OTEL_EXPORTER_OTLP_ENDPOINT", "http://jaeger:4318")
36
  sampling_rate = float(os.getenv("JAEGER_SAMPLING_RATE", "1.0"))
 
18
  logger = logging.getLogger(__name__)
19
 
20
 
21
+ def is_tracing_enabled() -> bool:
22
+ """
23
+ Check if tracing is enabled via ENABLE_TRACING environment variable.
24
+
25
+ Returns:
26
+ True if tracing is enabled (default), False otherwise
27
+ """
28
+ return os.getenv("ENABLE_TRACING", "true").lower() in ("true", "1", "yes")
29
+
30
+
31
  def init_tracer(service_name: str) -> trace.Tracer:
32
  """
33
  Initialize OpenTelemetry tracer with OTLP HTTP exporter for Jaeger.
 
35
  Uses HTTP protocol like the Go API (instead of unreliable UDP).
36
  Jaeger >= 1.35 supports OTLP natively on port 4318.
37
 
38
+ Can be disabled by setting ENABLE_TRACING=false environment variable.
39
+
40
  Args:
41
  service_name: Name of the service for tracing
42
 
43
  Returns:
44
+ Configured tracer instance (or no-op tracer if disabled)
45
  """
46
+ # Check if tracing is enabled
47
+ if not is_tracing_enabled():
48
+ print(f"[TRACING] Tracing disabled via ENABLE_TRACING environment variable")
49
+ logger.info("OpenTelemetry tracing disabled")
50
+ # Return default no-op tracer
51
+ return trace.get_tracer(service_name)
52
+
53
  # Jaeger OTLP HTTP endpoint (port 4318)
54
  otlp_endpoint = os.getenv("OTEL_EXPORTER_OTLP_ENDPOINT", "http://jaeger:4318")
55
  sampling_rate = float(os.getenv("JAEGER_SAMPLING_RATE", "1.0"))
test_tracing_toggle.py ADDED
@@ -0,0 +1,172 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env python3
2
+ """
3
+ Test script to verify ENABLE_TRACING toggle works correctly.
4
+
5
+ Usage:
6
+ # Test with tracing enabled (default)
7
+ python test_tracing_toggle.py
8
+
9
+ # Test with tracing disabled
10
+ ENABLE_TRACING=false python test_tracing_toggle.py
11
+ """
12
+ import os
13
+ import sys
14
+
15
+ # Add src to path
16
+ sys.path.insert(0, os.path.join(os.path.dirname(__file__), 'src'))
17
+
18
+ from utils.tracing import is_tracing_enabled, init_tracer
19
+
20
+
21
+ def test_is_tracing_enabled():
22
+ """Test the is_tracing_enabled function with various env values."""
23
+ print("Testing is_tracing_enabled()...")
24
+
25
+ test_cases = [
26
+ ("true", True),
27
+ ("True", True),
28
+ ("TRUE", True),
29
+ ("1", True),
30
+ ("yes", True),
31
+ ("YES", True),
32
+ ("false", False),
33
+ ("False", False),
34
+ ("FALSE", False),
35
+ ("0", False),
36
+ ("no", False),
37
+ ("NO", False),
38
+ ("", True), # Default is enabled
39
+ (None, True), # Default is enabled
40
+ ]
41
+
42
+ for value, expected in test_cases:
43
+ # Set or unset environment variable
44
+ if value is None:
45
+ os.environ.pop("ENABLE_TRACING", None)
46
+ else:
47
+ os.environ["ENABLE_TRACING"] = value
48
+
49
+ result = is_tracing_enabled()
50
+ status = "βœ“" if result == expected else "βœ—"
51
+ print(f" {status} ENABLE_TRACING={value!r} β†’ {result} (expected {expected})")
52
+
53
+ if result != expected:
54
+ return False
55
+
56
+ return True
57
+
58
+
59
+ def test_init_tracer():
60
+ """Test that init_tracer respects the ENABLE_TRACING flag."""
61
+ print("\nTesting init_tracer()...")
62
+
63
+ # Test with tracing disabled
64
+ os.environ["ENABLE_TRACING"] = "false"
65
+ os.environ["OTEL_EXPORTER_OTLP_ENDPOINT"] = "http://localhost:4318"
66
+
67
+ print(" Testing with ENABLE_TRACING=false...")
68
+ tracer = init_tracer("test-service")
69
+
70
+ # Should return a tracer (no-op) but not initialize OpenTelemetry
71
+ if tracer is None:
72
+ print(" βœ— init_tracer returned None (should return no-op tracer)")
73
+ return False
74
+
75
+ print(" βœ“ init_tracer returned tracer (no-op)")
76
+
77
+ # Test with tracing enabled
78
+ os.environ["ENABLE_TRACING"] = "true"
79
+ print(" Testing with ENABLE_TRACING=true...")
80
+
81
+ # Note: This will actually try to connect to Jaeger if available
82
+ # but won't fail if Jaeger is down
83
+ try:
84
+ tracer = init_tracer("test-service-enabled")
85
+ print(" βœ“ init_tracer returned tracer (full initialization)")
86
+ except Exception as e:
87
+ print(f" ⚠ init_tracer failed: {e}")
88
+ print(" (This is expected if Jaeger is not running)")
89
+
90
+ return True
91
+
92
+
93
+ def test_span_creation():
94
+ """Test that spans are created/skipped based on toggle."""
95
+ print("\nTesting span creation...")
96
+
97
+ from opentelemetry import trace
98
+
99
+ # Test with tracing disabled
100
+ os.environ["ENABLE_TRACING"] = "false"
101
+
102
+ if is_tracing_enabled():
103
+ print(" βœ— is_tracing_enabled() returned True when ENABLE_TRACING=false")
104
+ return False
105
+
106
+ # This should be a no-op
107
+ tracer = trace.get_tracer(__name__)
108
+ span = tracer.start_span("test-span")
109
+ span.end()
110
+ print(" βœ“ No-op span created successfully when disabled")
111
+
112
+ # Test with tracing enabled
113
+ os.environ["ENABLE_TRACING"] = "true"
114
+
115
+ if not is_tracing_enabled():
116
+ print(" βœ— is_tracing_enabled() returned False when ENABLE_TRACING=true")
117
+ return False
118
+
119
+ print(" βœ“ Tracing enabled check passed")
120
+
121
+ return True
122
+
123
+
124
+ def main():
125
+ """Run all tests."""
126
+ print("=" * 60)
127
+ print("ENABLE_TRACING Toggle Test Suite")
128
+ print("=" * 60)
129
+
130
+ current_value = os.environ.get("ENABLE_TRACING", "<not set>")
131
+ print(f"\nCurrent ENABLE_TRACING: {current_value}")
132
+ print()
133
+
134
+ tests = [
135
+ ("is_tracing_enabled()", test_is_tracing_enabled),
136
+ ("init_tracer()", test_init_tracer),
137
+ ("span creation", test_span_creation),
138
+ ]
139
+
140
+ results = []
141
+ for name, test_func in tests:
142
+ try:
143
+ success = test_func()
144
+ results.append((name, success))
145
+ except Exception as e:
146
+ print(f"\nβœ— Test '{name}' raised exception: {e}")
147
+ results.append((name, False))
148
+
149
+ # Print summary
150
+ print("\n" + "=" * 60)
151
+ print("Test Summary")
152
+ print("=" * 60)
153
+
154
+ passed = sum(1 for _, success in results if success)
155
+ total = len(results)
156
+
157
+ for name, success in results:
158
+ status = "βœ“ PASS" if success else "βœ— FAIL"
159
+ print(f"{status}: {name}")
160
+
161
+ print(f"\n{passed}/{total} tests passed")
162
+
163
+ if passed == total:
164
+ print("\nβœ“ All tests passed!")
165
+ return 0
166
+ else:
167
+ print(f"\nβœ— {total - passed} test(s) failed")
168
+ return 1
169
+
170
+
171
+ if __name__ == "__main__":
172
+ sys.exit(main())