{
  "schemaVersion": "1.0",
  "item": {
    "slug": "observability-lgtm",
    "name": "Observability Lgtm",
    "source": "tencent",
    "type": "skill",
    "category": "开发工具",
    "sourceUrl": "https://clawhub.ai/nissan/observability-lgtm",
    "canonicalUrl": "https://clawhub.ai/nissan/observability-lgtm",
    "targetPlatform": "OpenClaw"
  },
  "install": {
    "downloadMode": "redirect",
    "downloadUrl": "/downloads/observability-lgtm",
    "sourceDownloadUrl": "https://wry-manatee-359.convex.site/api/v1/download?slug=observability-lgtm",
    "sourcePlatform": "tencent",
    "targetPlatform": "OpenClaw",
    "installMethod": "Manual import",
    "extraction": "Extract archive",
    "prerequisites": [
      "OpenClaw"
    ],
    "packageFormat": "ZIP package",
    "includedAssets": [
      "SKILL.md",
      "assets/config/grafana/dashboards/fastapi-overview.json",
      "assets/config/grafana/provisioning/dashboards/dashboards.yml",
      "assets/config/grafana/provisioning/datasources/datasources.yml",
      "assets/config/loki/loki.yml",
      "assets/config/prometheus/prometheus.yml"
    ],
    "primaryDoc": "SKILL.md",
    "quickSetup": [
      "Download the package from Yavira.",
      "Extract the archive and review SKILL.md first.",
      "Import or place the package into your OpenClaw setup."
    ],
    "agentAssist": {
      "summary": "Hand the extracted package to your coding agent with a concrete install brief instead of figuring it out manually.",
      "steps": [
        "Download the package from Yavira.",
        "Extract it into a folder your agent can access.",
        "Paste one of the prompts below and point your agent at the extracted folder."
      ],
      "prompts": [
        {
          "label": "New install",
          "body": "I downloaded a skill package from Yavira. Read SKILL.md from the extracted folder and install it by following the included instructions. Tell me what you changed and call out any manual steps you could not complete."
        },
        {
          "label": "Upgrade existing",
          "body": "I downloaded an updated skill package from Yavira. Read SKILL.md from the extracted folder, compare it with my current installation, and upgrade it while preserving any custom configuration unless the package docs explicitly say otherwise. Summarize what changed and any follow-up checks I should run."
        }
      ]
    },
    "sourceHealth": {
      "source": "tencent",
      "slug": "observability-lgtm",
      "status": "healthy",
      "reason": "direct_download_ok",
      "recommendedAction": "download",
      "checkedAt": "2026-05-06T07:08:56.011Z",
      "expiresAt": "2026-05-13T07:08:56.011Z",
      "httpStatus": 200,
      "finalUrl": "https://wry-manatee-359.convex.site/api/v1/download?slug=observability-lgtm",
      "contentType": "application/zip",
      "probeMethod": "head",
      "details": {
        "probeUrl": "https://wry-manatee-359.convex.site/api/v1/download?slug=observability-lgtm",
        "contentDisposition": "attachment; filename=\"observability-lgtm-1.2.0.zip\"",
        "redirectLocation": null,
        "bodySnippet": null,
        "slug": "observability-lgtm"
      },
      "scope": "item",
      "summary": "Item download looks usable.",
      "detail": "Yavira can redirect you to the upstream package for this item.",
      "primaryActionLabel": "Download for OpenClaw",
      "primaryActionHref": "/downloads/observability-lgtm"
    },
    "validation": {
      "installChecklist": [
        "Use the Yavira download entry.",
        "Review SKILL.md after the package is downloaded.",
        "Confirm the extracted package contains the expected setup assets."
      ],
      "postInstallChecks": [
        "Confirm the extracted package includes the expected docs or setup files.",
        "Validate the skill or prompts are available in your target agent workspace.",
        "Capture any manual follow-up steps the agent could not complete."
      ]
    },
    "downloadPageUrl": "https://openagent3.xyz/downloads/observability-lgtm",
    "agentPageUrl": "https://openagent3.xyz/skills/observability-lgtm/agent",
    "manifestUrl": "https://openagent3.xyz/skills/observability-lgtm/agent.json",
    "briefUrl": "https://openagent3.xyz/skills/observability-lgtm/agent.md"
  },
  "agentAssist": {
    "summary": "Hand the extracted package to your coding agent with a concrete install brief instead of figuring it out manually.",
    "steps": [
      "Download the package from Yavira.",
      "Extract it into a folder your agent can access.",
      "Paste one of the prompts below and point your agent at the extracted folder."
    ],
    "prompts": [
      {
        "label": "New install",
        "body": "I downloaded a skill package from Yavira. Read SKILL.md from the extracted folder and install it by following the included instructions. Tell me what you changed and call out any manual steps you could not complete."
      },
      {
        "label": "Upgrade existing",
        "body": "I downloaded an updated skill package from Yavira. Read SKILL.md from the extracted folder, compare it with my current installation, and upgrade it while preserving any custom configuration unless the package docs explicitly say otherwise. Summarize what changed and any follow-up checks I should run."
      }
    ]
  },
  "documentation": {
    "source": "clawhub",
    "primaryDoc": "SKILL.md",
    "sections": [
      {
        "title": "observability-lgtm",
        "body": "Set up a full local observability stack (Loki + Grafana + Tempo + Prometheus + Alloy)\nfor FastAPI apps on macOS (Apple Silicon) or Linux. One command to start, one import\nto instrument any app. Logs → Loki, metrics → Prometheus, traces → Tempo, all\nunified in Grafana."
      },
      {
        "title": "When to use",
        "body": "User is building a FastAPI web app and wants logs, metrics, and traces\nUser wants a local Grafana dashboard without setting up ELK (too heavy)\nUser wants to correlate logs ↔ traces ↔ metrics in one UI\nUser has multiple local apps and wants universal observability"
      },
      {
        "title": "When NOT to use",
        "body": "Production cloud deployments (use managed Grafana Cloud or Datadog instead)\nNon-Python apps (the Python lib only works for FastAPI; the stack itself is language-agnostic)\nWhen Docker is not available"
      },
      {
        "title": "Prerequisites",
        "body": "Docker + Docker Compose v2 installed\nPython 3.10+ (for the instrumentation lib)\nFastAPI app to instrument"
      },
      {
        "title": "What gets installed",
        "body": "ServicePortPurposeGrafana3000Dashboards — no login in dev modePrometheus9091Metrics scraping (avoids 9090 if MinIO running)Loki3300Log storage (avoids 3100 if Langfuse running)Tempo gRPC4317OTLP trace receiverTempo HTTP4318OTLP HTTP alternativeAlloy UI12345Agent status"
      },
      {
        "title": "Step 1 — Check for port conflicts",
        "body": "lsof -iTCP -sTCP:LISTEN -n -P 2>/dev/null | grep -E \":(3000|3300|9091|4317|4318|12345)\" | awk '{print $9, $1}'\n\nIf any of the ports above are in use, update the relevant port in docker-compose.yml\nand the matching url: in config/grafana/provisioning/datasources/datasources.yml.\nCommon conflicts: Langfuse on 3100, MinIO on 9090."
      },
      {
        "title": "Step 2 — Copy the stack",
        "body": "Copy these files from the skill directory into a projects/observability/ folder\nin the workspace:\n\nassets/docker-compose.yml\nassets/config/ (entire directory tree)\nassets/lib/observability.py\nassets/scripts/register_app.sh\n\nmkdir -p projects/observability\ncp -r SKILL_DIR/assets/* projects/observability/\nmkdir -p projects/observability/logs\ntouch projects/observability/logs/.gitkeep\nchmod +x projects/observability/scripts/register_app.sh"
      },
      {
        "title": "Step 3 — Start the stack",
        "body": "cd projects/observability\ndocker compose up -d\n\nWait ~15 seconds for all services to start, then verify:\n\ncurl -s -o /dev/null -w \"Grafana: %{http_code}\\n\"    http://localhost:3000/api/health\ncurl -s -o /dev/null -w \"Prometheus: %{http_code}\\n\" http://localhost:9091/-/healthy\ncurl -s -o /dev/null -w \"Loki: %{http_code}\\n\"       http://localhost:3300/ready\ncurl -s -o /dev/null -w \"Tempo: %{http_code}\\n\"      http://localhost:4318/ready\n\nAll should return 200. If Loki or Tempo return 503, wait 10 more seconds and retry\n(they have a slower startup than Grafana/Prometheus)."
      },
      {
        "title": "Step 4 — Install Python deps for the app",
        "body": "pip install \\\n  \"prometheus-fastapi-instrumentator>=7.0.0\" \\\n  \"opentelemetry-sdk>=1.25.0\" \\\n  \"opentelemetry-exporter-otlp-proto-grpc>=1.25.0\" \\\n  \"opentelemetry-instrumentation-fastapi>=0.46b0\" \\\n  \"python-json-logger>=2.0.7\""
      },
      {
        "title": "Step 5 — Instrument the FastAPI app",
        "body": "Add to the app's app.py (or main.py), just after app = FastAPI(...):\n\nimport sys\nsys.path.insert(0, \"path/to/projects/observability/lib\")\nfrom observability import setup_observability\nlogger = setup_observability(app, service_name=\"my-service-name\")\n\nThat's it. The app now:\n\nExposes /metrics for Prometheus\nWrites JSON logs to projects/observability/logs/my-service-name/app.log\nSends traces to Tempo on localhost:4317"
      },
      {
        "title": "Step 6 — Register with Prometheus",
        "body": "cd projects/observability\n./scripts/register_app.sh my-service-name <port>\n# e.g.: ./scripts/register_app.sh image-gen-studio 7860\n\nPrometheus hot-reloads the target within 30 seconds. Verify:\n\ncurl -s \"http://localhost:9091/api/v1/targets\" | python3 -c \"\nimport json, sys\ndata = json.load(sys.stdin)\nfor t in data['data']['activeTargets']:\n    svc = t['labels'].get('service', '')\n    print(svc, '->', t['health'])\n\""
      },
      {
        "title": "Step 7 — Open Grafana",
        "body": "Open http://localhost:3000\n\nThe FastAPI — App Overview dashboard is pre-loaded. Select your service from\nthe dropdown at the top. You'll see:\n\nRequest rate (req/s)\nError rate (%)\nLatency p50/p95/p99\nRequests by endpoint\nHTTP status codes\nLive log panel (Loki)\n\nTo jump from a log line to its trace: click the trace_id link in the log detail panel.\nIt opens the full trace in Tempo automatically (datasource pre-wired)."
      },
      {
        "title": "Step 8 — Import additional dashboards (optional)",
        "body": "In Grafana → Dashboards → Import:\n\n16110 — FastAPI Observability (richer alternative to the built-in)\n13407 — Loki Logs Overview\n16112 — Tempo Service Graph (service dependency map)"
      },
      {
        "title": "Useful commands",
        "body": "# Reload Prometheus config after registering a new app:\ncurl -s -X POST http://localhost:9091/-/reload\n\n# Restart a single service without losing data:\ndocker compose -f projects/observability/docker-compose.yml restart grafana\n\n# Stop everything (data volumes preserved):\ndocker compose -f projects/observability/docker-compose.yml down\n\n# Nuclear reset (wipes all stored data):\ndocker compose -f projects/observability/docker-compose.yml down -v\n\n# Check Alloy log shipping status:\nopen http://localhost:12345"
      },
      {
        "title": "Manual tracing (optional)",
        "body": "from observability import get_tracer\ntracer = get_tracer(__name__)\n\n@app.get(\"/expensive-endpoint\")\nasync def handler():\n    with tracer.start_as_current_span(\"db-query\") as span:\n        span.set_attribute(\"db.table\", \"users\")\n        result = await db.query(...)\n    return result"
      },
      {
        "title": "Log/trace correlation",
        "body": "The OTel instrumentation injects trace_id into every log record. Grafana Loki\nis pre-configured with a derived field that turns \"trace_id\":\"abc123\" into a\nclickable link to the Tempo trace.\n\nTo manually include trace context in your own log calls:\n\nfrom opentelemetry import trace\n\ndef trace_ctx() -> dict:\n    ctx = trace.get_current_span().get_span_context()\n    return {\"trace_id\": format(ctx.trace_id, \"032x\")} if ctx.is_valid else {}\n\nlogger.info(\"Processing request\", extra=trace_ctx())"
      },
      {
        "title": "Notes",
        "body": "Logs are written to projects/observability/logs/<service>/app.log as JSON.\nAlloy tails these files and ships to Loki — no code changes needed beyond setup_observability().\nAll observability is local — no data leaves the machine.\ndata_classification: LOCAL_ONLY is the default for all traces/logs.\nThe Alloy config drops DEBUG-level logs by default. Edit config/alloy/config.alloy\nto remove the stage.drop block if you need debug logs."
      }
    ],
    "body": "observability-lgtm\n\nSet up a full local observability stack (Loki + Grafana + Tempo + Prometheus + Alloy) for FastAPI apps on macOS (Apple Silicon) or Linux. One command to start, one import to instrument any app. Logs → Loki, metrics → Prometheus, traces → Tempo, all unified in Grafana.\n\nWhen to use\nUser is building a FastAPI web app and wants logs, metrics, and traces\nUser wants a local Grafana dashboard without setting up ELK (too heavy)\nUser wants to correlate logs ↔ traces ↔ metrics in one UI\nUser has multiple local apps and wants universal observability\nWhen NOT to use\nProduction cloud deployments (use managed Grafana Cloud or Datadog instead)\nNon-Python apps (the Python lib only works for FastAPI; the stack itself is language-agnostic)\nWhen Docker is not available\nPrerequisites\nDocker + Docker Compose v2 installed\nPython 3.10+ (for the instrumentation lib)\nFastAPI app to instrument\nWhat gets installed\nService\tPort\tPurpose\nGrafana\t3000\tDashboards — no login in dev mode\nPrometheus\t9091\tMetrics scraping (avoids 9090 if MinIO running)\nLoki\t3300\tLog storage (avoids 3100 if Langfuse running)\nTempo gRPC\t4317\tOTLP trace receiver\nTempo HTTP\t4318\tOTLP HTTP alternative\nAlloy UI\t12345\tAgent status\nSteps\nStep 1 — Check for port conflicts\nlsof -iTCP -sTCP:LISTEN -n -P 2>/dev/null | grep -E \":(3000|3300|9091|4317|4318|12345)\" | awk '{print $9, $1}'\n\n\nIf any of the ports above are in use, update the relevant port in docker-compose.yml and the matching url: in config/grafana/provisioning/datasources/datasources.yml. Common conflicts: Langfuse on 3100, MinIO on 9090.\n\nStep 2 — Copy the stack\n\nCopy these files from the skill directory into a projects/observability/ folder in the workspace:\n\nassets/docker-compose.yml\nassets/config/ (entire directory tree)\nassets/lib/observability.py\nassets/scripts/register_app.sh\nmkdir -p projects/observability\ncp -r SKILL_DIR/assets/* projects/observability/\nmkdir -p projects/observability/logs\ntouch projects/observability/logs/.gitkeep\nchmod +x projects/observability/scripts/register_app.sh\n\nStep 3 — Start the stack\ncd projects/observability\ndocker compose up -d\n\n\nWait ~15 seconds for all services to start, then verify:\n\ncurl -s -o /dev/null -w \"Grafana: %{http_code}\\n\"    http://localhost:3000/api/health\ncurl -s -o /dev/null -w \"Prometheus: %{http_code}\\n\" http://localhost:9091/-/healthy\ncurl -s -o /dev/null -w \"Loki: %{http_code}\\n\"       http://localhost:3300/ready\ncurl -s -o /dev/null -w \"Tempo: %{http_code}\\n\"      http://localhost:4318/ready\n\n\nAll should return 200. If Loki or Tempo return 503, wait 10 more seconds and retry (they have a slower startup than Grafana/Prometheus).\n\nStep 4 — Install Python deps for the app\npip install \\\n  \"prometheus-fastapi-instrumentator>=7.0.0\" \\\n  \"opentelemetry-sdk>=1.25.0\" \\\n  \"opentelemetry-exporter-otlp-proto-grpc>=1.25.0\" \\\n  \"opentelemetry-instrumentation-fastapi>=0.46b0\" \\\n  \"python-json-logger>=2.0.7\"\n\nStep 5 — Instrument the FastAPI app\n\nAdd to the app's app.py (or main.py), just after app = FastAPI(...):\n\nimport sys\nsys.path.insert(0, \"path/to/projects/observability/lib\")\nfrom observability import setup_observability\nlogger = setup_observability(app, service_name=\"my-service-name\")\n\n\nThat's it. The app now:\n\nExposes /metrics for Prometheus\nWrites JSON logs to projects/observability/logs/my-service-name/app.log\nSends traces to Tempo on localhost:4317\nStep 6 — Register with Prometheus\ncd projects/observability\n./scripts/register_app.sh my-service-name <port>\n# e.g.: ./scripts/register_app.sh image-gen-studio 7860\n\n\nPrometheus hot-reloads the target within 30 seconds. Verify:\n\ncurl -s \"http://localhost:9091/api/v1/targets\" | python3 -c \"\nimport json, sys\ndata = json.load(sys.stdin)\nfor t in data['data']['activeTargets']:\n    svc = t['labels'].get('service', '')\n    print(svc, '->', t['health'])\n\"\n\nStep 7 — Open Grafana\n\nOpen http://localhost:3000\n\nThe FastAPI — App Overview dashboard is pre-loaded. Select your service from the dropdown at the top. You'll see:\n\nRequest rate (req/s)\nError rate (%)\nLatency p50/p95/p99\nRequests by endpoint\nHTTP status codes\nLive log panel (Loki)\n\nTo jump from a log line to its trace: click the trace_id link in the log detail panel. It opens the full trace in Tempo automatically (datasource pre-wired).\n\nStep 8 — Import additional dashboards (optional)\n\nIn Grafana → Dashboards → Import:\n\n16110 — FastAPI Observability (richer alternative to the built-in)\n13407 — Loki Logs Overview\n16112 — Tempo Service Graph (service dependency map)\nUseful commands\n# Reload Prometheus config after registering a new app:\ncurl -s -X POST http://localhost:9091/-/reload\n\n# Restart a single service without losing data:\ndocker compose -f projects/observability/docker-compose.yml restart grafana\n\n# Stop everything (data volumes preserved):\ndocker compose -f projects/observability/docker-compose.yml down\n\n# Nuclear reset (wipes all stored data):\ndocker compose -f projects/observability/docker-compose.yml down -v\n\n# Check Alloy log shipping status:\nopen http://localhost:12345\n\nManual tracing (optional)\nfrom observability import get_tracer\ntracer = get_tracer(__name__)\n\n@app.get(\"/expensive-endpoint\")\nasync def handler():\n    with tracer.start_as_current_span(\"db-query\") as span:\n        span.set_attribute(\"db.table\", \"users\")\n        result = await db.query(...)\n    return result\n\nLog/trace correlation\n\nThe OTel instrumentation injects trace_id into every log record. Grafana Loki is pre-configured with a derived field that turns \"trace_id\":\"abc123\" into a clickable link to the Tempo trace.\n\nTo manually include trace context in your own log calls:\n\nfrom opentelemetry import trace\n\ndef trace_ctx() -> dict:\n    ctx = trace.get_current_span().get_span_context()\n    return {\"trace_id\": format(ctx.trace_id, \"032x\")} if ctx.is_valid else {}\n\nlogger.info(\"Processing request\", extra=trace_ctx())\n\nNotes\nLogs are written to projects/observability/logs/<service>/app.log as JSON. Alloy tails these files and ships to Loki — no code changes needed beyond setup_observability().\nAll observability is local — no data leaves the machine.\ndata_classification: LOCAL_ONLY is the default for all traces/logs.\nThe Alloy config drops DEBUG-level logs by default. Edit config/alloy/config.alloy to remove the stage.drop block if you need debug logs."
  },
  "trust": {
    "sourceLabel": "tencent",
    "provenanceUrl": "https://clawhub.ai/nissan/observability-lgtm",
    "publisherUrl": "https://clawhub.ai/nissan/observability-lgtm",
    "owner": "nissan",
    "version": "1.2.0",
    "license": null,
    "verificationStatus": "Indexed source record"
  },
  "links": {
    "detailUrl": "https://openagent3.xyz/skills/observability-lgtm",
    "downloadUrl": "https://openagent3.xyz/downloads/observability-lgtm",
    "agentUrl": "https://openagent3.xyz/skills/observability-lgtm/agent",
    "manifestUrl": "https://openagent3.xyz/skills/observability-lgtm/agent.json",
    "briefUrl": "https://openagent3.xyz/skills/observability-lgtm/agent.md"
  }
}