Skip to content

Commit a897d79

Browse files
committed
Merge branch 'observability/add-local-o11y' into staging
2 parents 88d8d1e + 9cc4371 commit a897d79

52 files changed

Lines changed: 761 additions & 331 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.env

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,11 @@ FLASK_DEBUG=true
44
DEVEL=True
55
SECRET_KEY=local_development_fake_key
66
LP_API_USERNAME=test_lp_user
7+
8+
# OpenTelemetry
9+
# Uncomment to enable tracing:
10+
# OTEL_SERVICE_NAME=snapcraft-io
11+
# if using Linux, uncomment this:
12+
# OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4318
13+
# if using MacOS, uncomment this:
14+
# OTEL_EXPORTER_OTLP_ENDPOINT=http://host.docker.internal:4318

.github/workflows/coverage.yml

Lines changed: 79 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ name: Test coverage
22
on:
33
schedule:
44
- cron: "0 22 * * *"
5+
workflow_dispatch: # Allows manual triggering
56

67
jobs:
78
test:
@@ -39,68 +40,67 @@ jobs:
3940
- name: Zip coverage report
4041
run: |
4142
zip -r coverage/cobertura-coverage.zip coverage/cobertura-coverage.xml coverage/coverage.xml
42-
43+
4344
- name: Upload coverage report
4445
if: always()
4546
uses: actions/upload-artifact@v4
4647
with:
4748
name: snapcraftio-coverage
4849
path: coverage
4950
retention-days: 1
50-
51-
publish-coverage-report:
52-
name: publish-coverage-report
53-
runs-on: ubuntu-latest
54-
needs: test
55-
continue-on-error: true
56-
steps:
57-
- uses: actions/checkout@v4
58-
with:
59-
ref: gh-pages
60-
token: ${{ secrets.GITHUB_TOKEN }}
61-
- name: Cleanup coverage directory
62-
run: |
63-
rm -rf coverage
64-
mkdir coverage
65-
- name: Download coverage report artifact
66-
uses: actions/download-artifact@v4
67-
with:
68-
name: snapcraftio-coverage
69-
path: coverage
70-
# user git configs are needed for git commands to work
71-
# actual authentication is done using secrets.GITHUB_TOKEN with write permission
72-
- name: Set Git User
73-
run: |
74-
git config --global user.email "github-action@example.com"
75-
git config --global user.name "GitHub Action"
76-
- name: Push coverage Report
77-
timeout-minutes: 3
78-
run: |
79-
git add .
80-
git commit -m "workflow: update coverage report"
81-
82-
# In case of another action job pushing to gh-pages while we are rebasing for the current job
83-
while true; do
84-
git pull --rebase
85-
if [ $? -ne 0 ]; then
86-
echo "Failed to rebase. Please review manually."
87-
exit 1
88-
fi
89-
90-
git push
91-
if [ $? -eq 0 ]; then
92-
echo "Successfully pushed HTML report to repo."
93-
exit 0
94-
fi
95-
done
96-
- name: Output Report URL as Worfklow Annotation
97-
run: |
98-
FULL_HTML_REPORT_URL=https://canonical.github.io/snapcraft.io/coverage
99-
echo "::notice title=Published Playwright Test Report::$FULL_HTML_REPORT_URL"
10051

52+
publish-coverage-report:
53+
name: publish-coverage-report
54+
runs-on: ubuntu-latest
55+
needs: test
56+
continue-on-error: true
57+
steps:
58+
- uses: actions/checkout@v4
59+
with:
60+
ref: gh-pages
61+
token: ${{ secrets.GITHUB_TOKEN }}
62+
- name: Cleanup coverage directory
63+
run: |
64+
rm -rf coverage
65+
mkdir coverage
66+
- name: Download coverage report artifact
67+
uses: actions/download-artifact@v4
68+
with:
69+
name: snapcraftio-coverage
70+
path: coverage
71+
# user git configs are needed for git commands to work
72+
# actual authentication is done using secrets.GITHUB_TOKEN with write permission
73+
- name: Set Git User
74+
run: |
75+
git config --global user.email "github-action@example.com"
76+
git config --global user.name "GitHub Action"
77+
- name: Push coverage Report
78+
timeout-minutes: 3
79+
run: |
80+
git add .
81+
git commit -m "workflow: update coverage report"
82+
83+
# In case of another action job pushing to gh-pages while we are rebasing for the current job
84+
while true; do
85+
git pull --rebase
86+
if [ $? -ne 0 ]; then
87+
echo "Failed to rebase. Please review manually."
88+
exit 1
89+
fi
90+
91+
git push
92+
if [ $? -eq 0 ]; then
93+
echo "Successfully pushed HTML report to repo."
94+
exit 0
95+
fi
96+
done
97+
- name: Output Report URL as Worfklow Annotation
98+
run: |
99+
FULL_HTML_REPORT_URL=https://canonical.github.io/snapcraft.io/coverage
100+
echo "::notice title=Published Playwright Test Report::$FULL_HTML_REPORT_URL"
101101
102102
tics-report:
103-
runs-on: ubuntu-latest
103+
runs-on: [self-hosted, reactive, amd64, tiobe, noble]
104104
needs: publish-coverage-report
105105
steps:
106106
- uses: actions/checkout@v4
@@ -111,21 +111,35 @@ jobs:
111111
name: snapcraftio-coverage
112112
path: coverage
113113

114+
- name: Set up Python 3.10
115+
uses: actions/setup-python@v5
116+
with:
117+
python-version: "3.10"
118+
cache: "pip"
119+
120+
- name: Set up Node.js
121+
uses: actions/setup-node@v4
122+
with:
123+
node-version: "22"
124+
cache: "yarn"
125+
114126
- name: Install Python requirements
115127
run: |
116-
sudo pip3 install -r requirements.txt
117-
118-
- name: Install Python dependencies
119-
run: sudo pip3 install pylint
128+
python -m pip install --upgrade pip
129+
pip3 install -r requirements.txt
130+
pip3 install pylint
120131
121132
- name: Install JS dependencies
122-
run: yarn install --immutable
123-
124-
- name: Produce TICS report
125-
shell: bash
126133
run: |
127-
set -x
128-
export TICSAUTHTOKEN=${{ secrets.TICSAUTHTOKEN }}
129-
curl --silent --show-error "https://canonical.tiobe.com/tiobeweb/TICS/api/public/v1/fapi/installtics/Script?cfg=default&platform=linux&url=https://canonical.tiobe.com/tiobeweb/TICS/" > install_tics.sh
130-
. ./install_tics.sh
131-
TICSQServer -project snapcraft.io -tmpdir /tmp/tics -branchdir . -nosanity
134+
yarn install --immutable
135+
136+
- name: Run TICS analysis with github-action
137+
uses: tiobe/tics-github-action@v3
138+
with:
139+
mode: qserver
140+
project: snapcraft.io
141+
branchdir: .
142+
viewerUrl: https://canonical.tiobe.com/tiobeweb/TICS/api/cfg?name=default
143+
ticsAuthToken: ${{ secrets.TICSAUTHTOKEN }}
144+
installTics: true
145+

entrypoint

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,4 +8,9 @@ if [ "${FLASK_DEBUG}" = true ] || [ "${FLASK_DEBUG}" = 1 ]; then
88
RUN_COMMAND="${RUN_COMMAND} --reload --log-level debug --timeout 9999"
99
fi
1010

11+
# if OTEL_SERVICE_NAME is defined, inject OTEL sdk
12+
if [ -n "${OTEL_SERVICE_NAME}" ]; then
13+
RUN_COMMAND="${RUN_COMMAND} --config observability/observability.gunicorn.conf.py"
14+
fi
15+
1116
${RUN_COMMAND}

observability/README.md

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
# Local Tracing for charmhub.io
2+
3+
This guide explains how to test OpenTelemetry traces locally using OpenTelemetry, Grafana and Tempo.
4+
5+
*This setup is intended for local development and testing purposes only.*
6+
7+
## Overview
8+
9+
This setup enables observability for local development by capturing traces from the application and visualising them in Grafana, using Tempo as the backend.
10+
11+
## Prerequisites
12+
13+
- Docker and Docker Compose installed
14+
- A properly configured `.env` file
15+
16+
## Setup Instructions
17+
18+
### 1. Configure environment variables
19+
20+
In your `.env` file, make the following changes:
21+
22+
- Uncomment the appropriate `OTEL_EXPORTER_OTLP_ENDPOINT` based on your operating system.
23+
- Uncomment `OTEL_SERVICE_NAME` to enable tracing.
24+
25+
### 2. Start observability stack
26+
27+
Open a new terminal window and run:
28+
29+
`cd observability`
30+
`docker compose up -d`
31+
32+
This starts the OpenTelemetry Collector, Grafana and Tempo containers for tracing.
33+
34+
### 3. Run the application
35+
36+
Back in the main terminal (in the root of the project), run `dotrun`
37+
38+
### 4. Generate traces
39+
40+
Interact with the application by visiting various pages such as:
41+
42+
- Homepage (list of charms)
43+
- Charm pages
44+
- Login page
45+
- Publisher pages
46+
47+
These interactions will generate traces.
48+
49+
### 5. View traces in Grafana
50+
51+
Open Grafana in the browser at: http://localhost:3000
52+
53+
Login using the default credentials:
54+
55+
- Username: `admin`
56+
- Password: `admin`
57+
58+
Then:
59+
1. Go to `Explore`
60+
2. The Tempo datasource should be selected
61+
3. Click `Search`
62+
4. You should see a list of trace IDs
63+
5. Click on a trace ID to view detailed nested spans
64+
65+
### 6. Stop the observability stack
66+
Once you're done testing, you can shut down the containers:
67+
`cd observability`
68+
`docker compose down`
69+

observability/docker-compose.yaml

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
services:
2+
grafana:
3+
image: grafana/grafana:latest
4+
ports:
5+
- "3000:3000"
6+
volumes:
7+
- ./grafana/provisioning:/etc/grafana/provisioning
8+
depends_on:
9+
- tempo
10+
networks:
11+
- observability
12+
13+
prometheus:
14+
image: prom/prometheus:latest
15+
ports:
16+
- "9090:9090"
17+
volumes:
18+
- ./prometheus/prometheus.yml:/etc/prometheus/prometheus.yml
19+
networks:
20+
- observability
21+
22+
tempo:
23+
image: grafana/tempo:latest
24+
ports:
25+
- "3200:3200" # Tempo UI/query
26+
command: [ "-config.file=/etc/tempo.yaml" ]
27+
volumes:
28+
- ./tempo/tempo.yaml:/etc/tempo.yaml
29+
networks:
30+
- observability
31+
32+
otel-collector:
33+
image: otel/opentelemetry-collector-contrib:latest
34+
command: [ "--config=/etc/otel-collector-config.yaml" ]
35+
ports:
36+
- "4318:4318" # OTLP HTTP - app on localhost sends traces here
37+
volumes:
38+
- ./otel-collector/otel-collector-config.yaml:/etc/otel-collector-config.yaml
39+
depends_on:
40+
- tempo
41+
networks:
42+
- observability
43+
44+
networks:
45+
observability:
46+
driver: bridge
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
apiVersion: 1
2+
3+
datasources:
4+
- name: Tempo
5+
type: tempo
6+
access: proxy
7+
url: http://tempo:3200
8+
isDefault: true
9+
10+
- name: Prometheus
11+
type: prometheus
12+
access: proxy
13+
url: http://prometheus:9090
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
from opentelemetry import trace
2+
from opentelemetry.exporter.otlp.proto.http.trace_exporter import OTLPSpanExporter
3+
from opentelemetry.sdk.trace import TracerProvider
4+
from opentelemetry.sdk.trace.export import BatchSpanProcessor
5+
6+
7+
def post_fork(server, worker):
8+
trace.set_tracer_provider(TracerProvider())
9+
span_processor = BatchSpanProcessor(OTLPSpanExporter())
10+
trace.get_tracer_provider().add_span_processor(span_processor)
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
receivers:
2+
otlp:
3+
protocols:
4+
http:
5+
endpoint: "0.0.0.0:4318"
6+
7+
exporters:
8+
otlp:
9+
endpoint: tempo:4317
10+
tls:
11+
insecure: true
12+
13+
service:
14+
pipelines:
15+
traces:
16+
receivers: [otlp]
17+
exporters: [otlp]
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
global:
2+
scrape_interval: 10s
3+
4+
scrape_configs:
5+
- job_name: 'snapcraft-io'
6+
metrics_path: '/_status/metrics'
7+
static_configs:
8+
- targets: ['snapcraft.io']

observability/tempo/tempo.yaml

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
auth_enabled: false
2+
3+
server:
4+
http_listen_port: 3200
5+
6+
distributor:
7+
receivers:
8+
otlp:
9+
protocols:
10+
grpc:
11+
endpoint: 0.0.0.0:4317
12+
ingester:
13+
trace_idle_period: 10s
14+
max_block_bytes: 5_000_000
15+
max_block_duration: 5m
16+
17+
compactor:
18+
compaction:
19+
block_retention: 1h
20+
21+
storage:
22+
trace:
23+
backend: local
24+
local:
25+
path: /tmp/tempo/traces

0 commit comments

Comments
 (0)