1
+ import asyncio
2
+ import functions_framework
3
+ from flask import Request , jsonify
4
+ from opentelemetry import trace
5
+ from opentelemetry .sdk .trace import TracerProvider
6
+ from opentelemetry .sdk .trace .export import BatchSpanProcessor
7
+ from opentelemetry .exporter .otlp .proto .grpc .trace_exporter import OTLPSpanExporter
8
+ from opentelemetry .sdk .resources import Resource
9
+ from opentelemetry .semconv .resource import ResourceAttributes
10
+ from opentelemetry .instrumentation .asyncio import AsyncioInstrumentor
11
+
12
+ # Initialize OpenTelemetry components
13
+ def initialize_tracing ():
14
+ # Create a resource with service information
15
+ resource = Resource .create ({
16
+ ResourceAttributes .SERVICE_NAME : "cloud-function" ,
17
+ ResourceAttributes .SERVICE_VERSION : "0.1.0" ,
18
+ })
19
+
20
+ # Set up tracer provider with the resource
21
+ provider = TracerProvider (resource = resource )
22
+ trace .set_tracer_provider (provider )
23
+
24
+ # Configure the OTLP exporter
25
+ otlp_exporter = OTLPSpanExporter (
26
+ endpoint = {{ .Logs .WriteURL }},
27
+ headers = {
28
+ "authorization" :"{{ .Logs.AuthValue }}" ,
29
+ }
30
+ )
31
+
32
+ #span_processor = BatchSpanProcessor(ConsoleSpanExporter())
33
+ span_processor = BatchSpanProcessor ((otlp_exporter ))
34
+ provider .add_span_processor (span_processor )
35
+
36
+ AsyncioInstrumentor ().instrument ()
37
+
38
+ return trace .get_tracer (__name__ )
39
+
40
+ tracer = initialize_tracing ()
41
+
42
+ async def process_request (request_data ):
43
+ with tracer .start_as_current_span ("process_request" ) as span :
44
+ span .set_attribute ("request.data_size" , len (str (request_data )))
45
+
46
+ await asyncio .sleep (1 )
47
+
48
+ result = {"message" : "Processed asynchronously" , "data" : request_data }
49
+ return result
50
+
51
+ @functions_framework .http
52
+ def http_handler (request : Request ):
53
+ with tracer .start_as_current_span ("http_handler" , kind = trace .SpanKind .SERVER ) as span :
54
+ span .set_attribute ("http.method" , request .method )
55
+ span .set_attribute ("http.url" , request .url )
56
+ span .set_attribute ("http.route" , request .path )
57
+
58
+ if request .is_json :
59
+ request_data = request .get_json ()
60
+ else :
61
+ request_data = request .form .to_dict () if request .form else request .args .to_dict ()
62
+
63
+ with tracer .start_as_current_span ("extract_headers" ) as header_span :
64
+ headers = dict (request .headers )
65
+ header_span .set_attribute ("request.header_count" , len (headers ))
66
+
67
+ if 'traceparent' in headers :
68
+ header_span .set_attribute ("trace.parent_id" , headers ['traceparent' ])
69
+
70
+ try :
71
+ loop = asyncio .new_event_loop ()
72
+ asyncio .set_event_loop (loop )
73
+ result = loop .run_until_complete (process_request (request_data ))
74
+ loop .close ()
75
+
76
+ return jsonify (result )
77
+ except Exception as e :
78
+ with tracer .start_as_current_span ("error_handler" ) as error_span :
79
+ error_span .set_attribute ("error.type" , str (type (e ).__name__ ))
80
+ error_span .set_attribute ("error.message" , str (e ))
81
+ error_span .record_exception (e )
82
+
83
+ return jsonify ({"error" : str (e )}), 500
84
+
85
+ # For local testing
86
+ if __name__ == "__main__" :
87
+ import os
88
+
89
+ # Run the app locally with functions-framework
90
+ # Use: functions-framework --target http_handler --debug
91
+ print ("Run with: functions-framework --target http_handler --debug" )
0 commit comments