""" ═══════════════════════════════════════════════════════════ 📱 Example Flask App with OpenTelemetry ═══════════════════════════════════════════════════════════ Run with: python app.py Or with auto-instrumentation: opentelemetry-instrument python app.py """ import os import time import random import atexit from flask import Flask, jsonify, request from opentelemetry import trace from opentelemetry.trace import Status, StatusCode from opentelemetry.instrumentation.flask import FlaskInstrumentor # Initialize tracing BEFORE creating Flask app from tracing import init_tracing, get_tracer, shutdown init_tracing() tracer = get_tracer() app = Flask(__name__) # Auto-instrument Flask FlaskInstrumentor().instrument_app(app) # Register shutdown handler atexit.register(shutdown) # Simulated database users = [ {"id": 1, "name": "Alice", "email": "alice@example.com"}, {"id": 2, "name": "Bob", "email": "bob@example.com"}, {"id": 3, "name": "Charlie", "email": "charlie@example.com"}, ] @app.route('/health') def health(): """Health check endpoint.""" return jsonify({"status": "healthy", "service": "python-example"}) @app.route('/users') def get_users(): """Get all users with custom span.""" with tracer.start_as_current_span("db.query.users") as span: span.set_attribute("db.system", "memory") span.set_attribute("db.operation", "SELECT") # Simulate database latency time.sleep(random.uniform(0.01, 0.1)) span.set_attribute("db.row_count", len(users)) span.set_status(Status(StatusCode.OK)) return jsonify({"users": users}) @app.route('/users/') def get_user(user_id: int): """Get user by ID.""" with tracer.start_as_current_span("db.query.user_by_id") as span: span.set_attribute("db.system", "memory") span.set_attribute("db.operation", "SELECT") span.set_attribute("user.id", user_id) # Simulate database latency time.sleep(random.uniform(0.01, 0.05)) user = next((u for u in users if u["id"] == user_id), None) if not user: span.set_status(Status(StatusCode.ERROR, "User not found")) return jsonify({"error": "User not found"}), 404 span.set_status(Status(StatusCode.OK)) return jsonify({"user": user}) @app.route('/orders', methods=['POST']) def create_order(): """Create order with nested spans.""" with tracer.start_as_current_span("order.create") as parent_span: try: data = request.get_json() or {} items = data.get("items", []) # Step 1: Validate inventory with tracer.start_as_current_span("inventory.check") as span: span.set_attribute("order.items", len(items)) time.sleep(random.uniform(0.05, 0.1)) span.set_status(Status(StatusCode.OK)) # Step 2: Process payment with tracer.start_as_current_span("payment.process") as span: span.set_attribute("payment.method", "credit_card") time.sleep(random.uniform(0.1, 0.2)) span.set_status(Status(StatusCode.OK)) # Step 3: Create order record with tracer.start_as_current_span("db.insert.order") as span: time.sleep(random.uniform(0.02, 0.05)) order_id = hex(int(time.time() * 1000))[2:] span.set_attribute("order.id", order_id) span.set_status(Status(StatusCode.OK)) parent_span.set_status(Status(StatusCode.OK)) return jsonify({"orderId": order_id, "status": "created"}) except Exception as e: parent_span.set_status(Status(StatusCode.ERROR, str(e))) parent_span.record_exception(e) return jsonify({"error": str(e)}), 500 @app.route('/error') def trigger_error(): """Trigger error for testing.""" span = trace.get_current_span() error = Exception("Simulated error for testing") span.record_exception(error) span.set_status(Status(StatusCode.ERROR, str(error))) return jsonify({"error": str(error)}), 500 @app.route('/external-call') def external_call(): """Make external HTTP call (demonstrates distributed tracing).""" import requests with tracer.start_as_current_span("external.http.call") as span: span.set_attribute("http.url", "https://httpbin.org/get") try: # Note: requests auto-instrumentation propagates trace context response = requests.get("https://httpbin.org/get", timeout=5) span.set_attribute("http.status_code", response.status_code) span.set_status(Status(StatusCode.OK)) return jsonify({"status": "ok", "external_status": response.status_code}) except Exception as e: span.record_exception(e) span.set_status(Status(StatusCode.ERROR, str(e))) return jsonify({"error": str(e)}), 500 if __name__ == '__main__': port = int(os.getenv('PORT', 5000)) print(f""" 🚀 Example app listening on http://localhost:{port} Try these endpoints: GET http://localhost:{port}/health GET http://localhost:{port}/users GET http://localhost:{port}/users/1 POST http://localhost:{port}/orders GET http://localhost:{port}/error GET http://localhost:{port}/external-call """) app.run(host='0.0.0.0', port=port, debug=False)