feat: add lab SQLite migrate, LiteLLM env, and OTEL/Grafana stack
sonar / sonar (push) Skipped
sonar / sonar (pull_request) Failing after 40s

Enable local workshop readiness with executable SQLite migrations, OpenTelemetry hello signals, and a provisioned Grafana demo dashboard over Tempo/Loki/Prometheus.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-08-11 14:58:33 -03:00
co-authored by Cursor
parent 5307e2a9fa
commit 3b5c3fb86f
19 changed files with 1487 additions and 6 deletions
@@ -0,0 +1,12 @@
apiVersion: 1
providers:
- name: ticketlab
orgId: 1
folder: TicketLab
type: file
disableDeletion: false
updateIntervalSeconds: 10
allowUiUpdates: true
options:
path: /etc/grafana/provisioning/dashboards/json
@@ -0,0 +1,155 @@
{
"annotations": { "list": [] },
"editable": true,
"fiscalYearStartMonth": 0,
"graphTooltip": 1,
"id": null,
"links": [],
"panels": [
{
"type": "row",
"title": "Metrics",
"gridPos": { "h": 1, "w": 24, "x": 0, "y": 0 },
"id": 10,
"collapsed": false
},
{
"id": 1,
"title": "Hello runs (total)",
"type": "stat",
"gridPos": { "h": 6, "w": 6, "x": 0, "y": 1 },
"datasource": { "type": "prometheus", "uid": "prometheus" },
"targets": [
{
"refId": "A",
"expr": "otelcol_ticketlab_hello_runs_total{exported_job=\"ticketlab\"}",
"legendFormat": "runs"
}
],
"options": {
"reduceOptions": { "calcs": ["lastNotNull"], "fields": "", "values": false },
"colorMode": "value",
"graphMode": "area",
"justifyMode": "auto",
"orientation": "auto",
"textMode": "auto"
},
"fieldConfig": {
"defaults": {
"color": { "mode": "thresholds" },
"thresholds": {
"mode": "absolute",
"steps": [
{ "color": "blue", "value": null },
{ "color": "green", "value": 1 }
]
},
"unit": "short"
},
"overrides": []
}
},
{
"id": 2,
"title": "Hello runs over time",
"type": "timeseries",
"gridPos": { "h": 6, "w": 18, "x": 6, "y": 1 },
"datasource": { "type": "prometheus", "uid": "prometheus" },
"targets": [
{
"refId": "A",
"expr": "otelcol_ticketlab_hello_runs_total{exported_job=\"ticketlab\"}",
"legendFormat": "{{component}}"
}
],
"fieldConfig": {
"defaults": {
"color": { "mode": "palette-classic" },
"custom": {
"drawStyle": "line",
"lineInterpolation": "smooth",
"fillOpacity": 15,
"showPoints": "auto",
"spanNulls": true
},
"unit": "short"
},
"overrides": []
},
"options": {
"legend": { "displayMode": "list", "placement": "bottom", "showLegend": true },
"tooltip": { "mode": "single", "sort": "none" }
}
},
{
"type": "row",
"title": "Logs",
"gridPos": { "h": 1, "w": 24, "x": 0, "y": 7 },
"id": 11,
"collapsed": false
},
{
"id": 3,
"title": "TicketLab logs (Loki)",
"type": "logs",
"gridPos": { "h": 10, "w": 24, "x": 0, "y": 8 },
"datasource": { "type": "loki", "uid": "loki" },
"targets": [
{
"refId": "A",
"expr": "{service_name=\"ticketlab\"}",
"queryType": "range"
}
],
"options": {
"showTime": true,
"showLabels": true,
"showCommonLabels": false,
"wrapLogMessage": true,
"prettifyLogMessage": true,
"enableLogDetails": true,
"dedupStrategy": "none",
"sortOrder": "Descending"
}
},
{
"type": "row",
"title": "Tracing",
"gridPos": { "h": 1, "w": 24, "x": 0, "y": 18 },
"id": 12,
"collapsed": false
},
{
"id": 4,
"title": "Recent traces (Tempo)",
"type": "table",
"gridPos": { "h": 10, "w": 24, "x": 0, "y": 19 },
"datasource": { "type": "tempo", "uid": "tempo" },
"targets": [
{
"refId": "A",
"datasource": { "type": "tempo", "uid": "tempo" },
"queryType": "traceql",
"query": "{ resource.service.name = \"ticketlab\" }",
"limit": 20,
"tableType": "traces"
}
],
"options": {
"showHeader": true,
"cellHeight": "sm",
"footer": { "show": false }
}
}
],
"refresh": "5s",
"schemaVersion": 39,
"tags": ["ticketlab", "otel", "demo"],
"templating": { "list": [] },
"time": { "from": "now-1h", "to": "now" },
"timepicker": {},
"timezone": "browser",
"title": "TicketLab Demo - Metrics / Logs / Traces",
"uid": "ticketlab-demo",
"version": 1
}
@@ -0,0 +1,43 @@
apiVersion: 1
datasources:
- name: Prometheus
type: prometheus
uid: prometheus
access: proxy
url: http://prometheus:9090
isDefault: true
editable: false
- name: Loki
type: loki
uid: loki
access: proxy
url: http://loki:3100
editable: false
jsonData:
derivedFields:
- datasourceUid: tempo
matcherRegex: '"trace_id":"(\w+)"'
name: TraceID
url: "$${__value.raw}"
urlDisplayLabel: View trace
- name: Tempo
type: tempo
uid: tempo
access: proxy
url: http://tempo:3200
editable: false
jsonData:
tracesToLogsV2:
datasourceUid: loki
spanStartTimeShift: "-1h"
spanEndTimeShift: "1h"
filterByTraceID: true
serviceMap:
datasourceUid: prometheus
nodeGraph:
enabled: true
lokiSearch:
datasourceUid: loki
+35
View File
@@ -0,0 +1,35 @@
auth_enabled: false
server:
http_listen_port: 3100
common:
instance_addr: 127.0.0.1
path_prefix: /loki
storage:
filesystem:
chunks_directory: /loki/chunks
rules_directory: /loki/rules
replication_factor: 1
ring:
kvstore:
store: inmemory
schema_config:
configs:
- from: 2024-01-01
store: tsdb
object_store: filesystem
schema: v13
index:
prefix: index_
period: 24h
storage_config:
filesystem:
directory: /loki/chunks
limits_config:
allow_structured_metadata: true
reject_old_samples: true
reject_old_samples_max_age: 168h
+41
View File
@@ -0,0 +1,41 @@
receivers:
otlp:
protocols:
grpc:
endpoint: 0.0.0.0:4317
http:
endpoint: 0.0.0.0:4318
processors:
batch: {}
exporters:
otlp/tempo:
endpoint: tempo:4317
tls:
insecure: true
loki:
endpoint: http://loki:3100/loki/api/v1/push
prometheus:
endpoint: 0.0.0.0:8889
namespace: otelcol
debug:
verbosity: basic
service:
pipelines:
traces:
receivers: [otlp]
processors: [batch]
exporters: [otlp/tempo, debug]
logs:
receivers: [otlp]
processors: [batch]
exporters: [loki, debug]
metrics:
receivers: [otlp]
processors: [batch]
exporters: [prometheus, debug]
+14
View File
@@ -0,0 +1,14 @@
global:
scrape_interval: 15s
scrape_configs:
# App TicketLab on the host (when GET /metrics exists)
- job_name: ticketlab
metrics_path: /metrics
static_configs:
- targets: ["host.docker.internal:3000"]
# OTEL Collector internal metrics
- job_name: otel-collector
static_configs:
- targets: ["otel-collector:8889"]
+39
View File
@@ -0,0 +1,39 @@
server:
http_listen_port: 3200
distributor:
receivers:
otlp:
protocols:
grpc:
endpoint: 0.0.0.0:4317
http:
endpoint: 0.0.0.0:4318
ingester:
trace_idle_period: 10s
max_block_duration: 5m
compactor:
compaction:
block_retention: 24h
storage:
trace:
backend: local
wal:
path: /var/tempo/wal
local:
path: /var/tempo/blocks
metrics_generator:
registry:
external_labels:
source: tempo
storage:
path: /var/tempo/generator/wal
overrides:
defaults:
metrics_generator:
processors: [service-graphs, span-metrics]