Skip to content

Commit c03eaa0

Browse files
adding the sample for gcp cloud function (#71)
1 parent 773a255 commit c03eaa0

File tree

5 files changed

+147
-2
lines changed

5 files changed

+147
-2
lines changed

python/fastapi/README.md

+2-2
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ opentelemetry-instrument python app.py
6565
- GET `/` - Hello World
6666
- GET `/items/:id` - Get items by ID
6767

68-
6. Sign in to [Last9 Dashboard](https://app.last9.io) and visit the APM
69-
dashboard to see the traces and metrics in action.
68+
7. Sign in to [Last9 Dashboard](https://app.last9.io) and visit the APM
69+
dashboard to see the traces in action.
7070

7171
![Traces](./traces.png)

python/gcp_cloud_function/README.md

+45
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
# Instrumentating Google cloud function using OpenTelemetry
2+
3+
This example demonstrates how to instrument a Google cloud function with OpenTelemetry.
4+
5+
1. Create a virtual environment and install the dependencies:
6+
7+
```bash
8+
python -m venv .venv
9+
source .venv/bin/activate
10+
pip install -r requirements.txt
11+
```
12+
13+
2. Install the Auto Instrumentation packages using the `opentelemetry-bootstrap`
14+
tool:
15+
16+
```bash
17+
opentelemetry-bootstrap -a requirements
18+
```
19+
It will output the packages that you can add to `requirements.txt`.
20+
21+
```bash
22+
opentelemetry-api>=1.15.0
23+
opentelemetry-sdk>=1.15.0
24+
opentelemetry-exporter-otlp>=1.15.0
25+
opentelemetry-distro==0.48b0
26+
opentelemetry-instrumentation==0.51b0
27+
opentelemetry-instrumentation-aiohttp-client==0.51b0
28+
opentelemetry-instrumentation-asyncio==0.51b0
29+
```
30+
31+
3. Obtain the OTLP Auth Header from the [Last9 dashboard](https://app.last9.io) and update the code.
32+
33+
4. Run the application:
34+
35+
```bash
36+
functions-framework --target http_handler --debug
37+
```
38+
39+
5. Once the server is running, you can access the application at
40+
`http://127.0.0.1:8080` by default.
41+
42+
6. Sign in to [Last9 Dashboard](https://app.last9.io) and visit the APM
43+
dashboard to see the traces in action.
44+
45+
![Traces](./traces.png)

python/gcp_cloud_function/Traces.png

86.9 KB
Loading

python/gcp_cloud_function/main.py

+91
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
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")
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
flask==3.0.3
2+
functions-framework==3.8.2
3+
opentelemetry-api>=1.15.0
4+
opentelemetry-sdk>=1.15.0
5+
opentelemetry-exporter-otlp>=1.15.0
6+
opentelemetry-distro==0.48b0
7+
opentelemetry-instrumentation==0.51b0
8+
opentelemetry-instrumentation-aiohttp-client==0.51b0
9+
opentelemetry-instrumentation-asyncio==0.51b0

0 commit comments

Comments
 (0)