Skip to content

Commit b748e1b

Browse files
committed
make dash0 optional for the demos to be published on otel blog
Signed-off-by: Kasper Borg Nissen <kasper.nissen@dash0.com>
1 parent 4e9d2e7 commit b748e1b

20 files changed

Lines changed: 1674 additions & 148 deletions

contour/README.md

Lines changed: 42 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11
# Contour with OpenTelemetry
22

3-
Demonstrates Contour ingress controller with OpenTelemetry metrics, tracing, and logs using Dash0.
3+
Demonstrates Contour ingress controller with OpenTelemetry metrics, tracing, and logs using a local observability stack and/or Dash0.
44

55
## What it does
66

77
- Creates a multi-node Kind cluster with Contour/Envoy
8+
- Deploys local observability stack: Jaeger, Prometheus, and OpenSearch
89
- Configures OTLP metrics, distributed tracing, and JSON access logs
9-
- Deploys OpenTelemetry Collectors (DaemonSet + Deployment) with trace-logs correlation
10+
- Deploys OpenTelemetry Collectors (DaemonSet + Deployment) with dual export to Dash0 and local stack
1011
- Includes Node.js demo application with auto-instrumentation
1112
- Uses Gateway API with HTTPRoute for modern, standards-based routing
1213

@@ -16,6 +17,7 @@ Demonstrates Contour ingress controller with OpenTelemetry metrics, tracing, and
1617
- Kind
1718
- kubectl
1819
- Helm 3
20+
- Optional: Dash0 account with API token
1921

2022
## Setup
2123

@@ -39,6 +41,44 @@ Demonstrates Contour ingress controller with OpenTelemetry metrics, tracing, and
3941
- **Logs**: JSON structured access logs with automatic trace_id/span_id extraction for correlation
4042
- **Gateway API**: Modern Kubernetes networking with GatewayClass, Gateway, and HTTPRoute resources
4143

44+
## Accessing Telemetry
45+
46+
The demo sends telemetry to both Dash0 (if configured) and a local observability stack for offline inspection.
47+
48+
### Dash0 (Optional)
49+
If you configured Dash0 credentials, log in to your Dash0 dashboard to view:
50+
- **Traces**: Filter by `service.name = "contour"` or `"envoy"`
51+
- **Metrics**: Search for `envoy_*` and `contour_*` metrics
52+
- **Logs**: Access logs with correlated trace IDs
53+
54+
### Local Observability Stack
55+
56+
**Jaeger (Traces):**
57+
```bash
58+
kubectl port-forward -n default svc/jaeger-query 16686:16686
59+
```
60+
Visit: http://localhost:16686
61+
62+
**Prometheus (Metrics):**
63+
```bash
64+
kubectl port-forward -n default svc/prometheus 9090:9090
65+
```
66+
Visit: http://localhost:9090
67+
68+
**OpenSearch Dashboards (Logs):**
69+
```bash
70+
kubectl port-forward -n default svc/opensearch-dashboards 5601:5601
71+
```
72+
Visit: http://localhost:5601
73+
- Username: `admin`
74+
- Password: `SecureP@ssw0rd123`
75+
76+
To view logs in OpenSearch Dashboards:
77+
1. Navigate to "Discover" in the left menu
78+
2. Create an index pattern: `otel-logs*`
79+
3. Select `@timestamp` as the time field
80+
4. Explore the logs with trace correlation
81+
4282
## Load Testing
4383

4484
Generate traffic to test observability:
Lines changed: 162 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,162 @@
1+
mode: daemonset
2+
image:
3+
repository: otel/opentelemetry-collector-contrib
4+
5+
resources:
6+
limits:
7+
memory: 512Mi
8+
requests:
9+
memory: 256Mi
10+
11+
clusterRole:
12+
create: true
13+
rules:
14+
- apiGroups: [""]
15+
resources: ["nodes/proxy"]
16+
verbs: ["get"]
17+
18+
tolerations:
19+
- key: node-role.kubernetes.io/control-plane
20+
operator: Exists
21+
effect: NoSchedule
22+
23+
presets:
24+
logsCollection:
25+
enabled: true
26+
kubernetesAttributes:
27+
enabled: true
28+
kubeletMetrics:
29+
enabled: true
30+
hostMetrics:
31+
enabled: true
32+
33+
config:
34+
processors:
35+
# Memory limiter to prevent OOM
36+
memory_limiter:
37+
check_interval: 2s
38+
limit_percentage: 75
39+
spike_limit_percentage: 15
40+
41+
# Transform processor to extract trace_id and span_id from JSON traceparent field (Contour/Envoy logs only)
42+
transform/trace-extract:
43+
log_statements:
44+
- context: log
45+
statements:
46+
# Parse JSON body if it's a string and contains traceparent
47+
- set(attributes["parsed_body"], ParseJSON(body)) where IsString(body) and IsMatch(body, "^\\{.*\\}$") and IsMatch(body, ".*traceparent.*")
48+
# Only process logs that have traceparent field
49+
- set(trace_id.string, Substring(attributes["parsed_body"]["traceparent"], 3, 32)) where attributes["parsed_body"]["traceparent"] != nil and IsMatch(attributes["parsed_body"]["traceparent"], "^00-[a-f0-9]{32}-[a-f0-9]{16}-[0-9a-f]{2}$")
50+
- set(span_id.string, Substring(attributes["parsed_body"]["traceparent"], 36, 16)) where attributes["parsed_body"]["traceparent"] != nil and IsMatch(attributes["parsed_body"]["traceparent"], "^00-[a-f0-9]{32}-[a-f0-9]{16}-[0-9a-f]{2}$")
51+
# Update the body only for logs that had traceparent
52+
- set(body, attributes["parsed_body"]) where attributes["parsed_body"]["traceparent"] != nil
53+
54+
# Batch processor for efficient export
55+
batch:
56+
timeout: 5s
57+
send_batch_size: 512
58+
59+
k8sattributes:
60+
extract:
61+
metadata:
62+
- k8s.namespace.name
63+
- k8s.deployment.name
64+
- k8s.replicaset.name
65+
- k8s.statefulset.name
66+
- k8s.daemonset.name
67+
- k8s.cronjob.name
68+
- k8s.job.name
69+
- k8s.node.name
70+
- k8s.pod.name
71+
- k8s.pod.uid
72+
- k8s.pod.start_time
73+
- k8s.container.name
74+
# Disabled labels/annotations to avoid OpenSearch mapping conflicts
75+
# labels:
76+
# - from: pod
77+
# key_regex: (.*)
78+
# tag_name: k8s.pod.label.$${1}
79+
# annotations:
80+
# - from: pod
81+
# key_regex: (.*)
82+
# tag_name: k8s.pod.annotation.$${1}
83+
filter:
84+
node_from_env_var: K8S_NODE_NAME
85+
passthrough: false
86+
pod_association:
87+
- sources:
88+
- from: resource_attribute
89+
name: k8s.pod.ip
90+
- sources:
91+
- from: resource_attribute
92+
name: k8s.pod.uid
93+
- sources:
94+
- from: connection
95+
96+
receivers:
97+
kubeletstats:
98+
insecure_skip_verify: true # For testing purposes. Remove for production.
99+
metrics:
100+
container.cpu.usage:
101+
enabled: true
102+
k8s.node.cpu.usage:
103+
enabled: true
104+
k8s.pod.cpu.usage:
105+
enabled: true
106+
k8s.pod.cpu_limit_utilization:
107+
enabled: true
108+
k8s.pod.cpu_request_utilization:
109+
enabled: true
110+
k8s.pod.memory_limit_utilization:
111+
enabled: true
112+
k8s.pod.memory_request_utilization:
113+
enabled: true
114+
115+
exporters:
116+
# Forward to deployment collector for local stack export
117+
otlp:
118+
endpoint: otel-collector-opentelemetry-collector.opentelemetry.svc.cluster.local:4317
119+
tls:
120+
insecure: true
121+
122+
# OpenSearch exporter (local logs)
123+
opensearch/log:
124+
http:
125+
endpoint: https://opensearch-cluster-master.default.svc.cluster.local:9200
126+
auth:
127+
authenticator: basicauth/opensearch
128+
tls:
129+
insecure_skip_verify: true
130+
logs_index: otel-logs
131+
132+
extensions:
133+
basicauth/opensearch:
134+
client_auth:
135+
username: admin
136+
password: "SecureP@ssw0rd123"
137+
138+
service:
139+
extensions:
140+
- basicauth/opensearch
141+
- health_check
142+
pipelines:
143+
logs:
144+
processors:
145+
- memory_limiter
146+
- k8sattributes
147+
- transform/trace-extract
148+
- batch
149+
exporters:
150+
- opensearch/log
151+
metrics:
152+
processors:
153+
- memory_limiter
154+
- batch
155+
exporters:
156+
- otlp
157+
traces:
158+
processors:
159+
- memory_limiter
160+
- batch
161+
exporters:
162+
- otlp

0 commit comments

Comments
 (0)