Skip to content

Jaeger - #108

Open
adamkinniburgh wants to merge 2 commits into
mainfrom
work/ak/jaeger
Open

Jaeger#108
adamkinniburgh wants to merge 2 commits into
mainfrom
work/ak/jaeger

Conversation

@adamkinniburgh

@adamkinniburgh adamkinniburgh commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

🔌 Plugin overview

  • Plugin name: Jaeger
  • Purpose / problem solved: Monitor services, dependencies, operations, and traces from a Jaeger distributed tracing backend, via its Query API — an auto-discovered service map, a call-dependency graph with call counts, and per-service operation/trace drilldown with duration, kind, and status.
  • Primary audience: Platform teams / SREs / backend engineers running Jaeger for distributed tracing who want it visible alongside their other infrastructure in SquaredUp.
  • Authentication method(s): None — Jaeger's Query API has no built-in authentication. Hybrid plugin: supports both cloud mode (direct) and relay agent mode (for private/firewalled Jaeger deployments).

🖼️ Plugin screenshots

Plugin configuration

to add

Default dashboards

to add


🧪 Testing

Tested end-to-end against a real deployed tenant, running against an actual on-prem Jaeger instance via the relay agent (not just structural validation).

  • Verified the services and dependencies streams directly via squaredup test against live data, including diagnosing and fixing a real indexing failure: the dependencies stream's original custom lookback parameter had no fallback, so when invoked by indexDefinitions/default.json (no dashboard tile context) it went out unbounded and timed out the connector. Switched dependencies over to the standard dashboard timeframe mechanism (matching traces) instead of a bespoke control, restricted to last1hourlast7days since the dependency-graph query is comparatively expensive, and added a safe fallback for the timeframe-less indexing context.
  • operations and traces verified directly against the live tenant.
  • Reviewed and fixed two real bugs in traces.js's OTLP decoding found during review: a duration-precision bug (rounding start/end to milliseconds independently before subtracting, rather than computing the duration in full nanosecond precision first) that could overstate short spans' duration by up to 1ms, and a SPAN_KIND default-value bug where proto3 JSON's omission of default-valued fields meant an INTERNAL/unspecified-kind span (very common) rendered as the literal string "undefined" instead of "UNSPECIFIED".
  • Confirmed (via Jaeger's own upstream test fixtures) that /api/v3/traces returns traceId/spanId as hex strings, not base64 — so no conversion was needed there, despite that being a real risk for a generic OTLP-JSON consumer.
  • Renamed source types (Jaeger Service/Jaeger DependencyService/Dependency) to follow the platform's non-prefixed source-type convention, propagated consistently across every referencing file in one pass.

⚠️ Known limitations

  • Dependencies' selectable timeframe is restricted to last 1 hour–last 7 days — the dependency-graph query is comparatively expensive on some storage backends, so it's deliberately narrower than Traces' full range.
  • Scheduled indexing of Dependencies always uses a 30 minute trailing window (imports run every 12 hours by default) since indexing has no dashboard timeframe context — a dependency that only occurred outside that trailing hour won't be indexed until it recurs. Correlation rules will remove this limitation in the near future.
  • Traces are per-service only — no cross-service trace search or single-trace detail view in this version.
  • No Service Performance Monitoring (SPM) metrics — SPM requires a separate metrics storage backend most Jaeger deployments don't enable.
  • No authentication — the Jaeger Query API has none; this plugin can't authenticate through a reverse proxy that requires it.
  • Dependency and Service objects aren't correlated (no edge between them) — a Dependency is really edge-shaped data (a call relationship), not a node, and the platform doesn't yet support importing data streams directly as graph edges. Revisit once that lands rather than forcing it through a same-plugin correlation rule now.
  • Read-only — the plugin never creates, modifies, or deletes anything in Jaeger.

📚 Checklist

  • Plugin, datastream and UI naming follow SquaredUp guidelines
  • Logo added
  • One or more dashboards added
  • README added including configuration guidance
  • No secrets or credentials included
  • I agree to the Code of Conduct

Summary by CodeRabbit

Summary by CodeRabbit

  • New Features

    • Added Jaeger v1 integration for services, dependencies, operations, and distributed traces.
    • Added configurable Query service URL and optional certificate validation bypass.
    • Added Overview and Service dashboards with service counts, dependency metrics, operations, and traces.
    • Added service selection, trace search-depth, and trace-count controls.
    • Added connection validation and indexing for Jaeger services and dependencies.
  • Documentation

    • Added setup guidance, supported data streams, configuration details, and known limitations.

@adamkinniburgh
adamkinniburgh requested a review from a team August 6, 2026 13:58
@adamkinniburgh adamkinniburgh added the new-plugin Used to PR newly added plugins label Aug 6, 2026
@coderabbitai

coderabbitai Bot commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

Jaeger v1 adds WebAPI connection settings, service and dependency indexing, operations and trace data streams, OTLP trace parsing, index definitions, scopes, dashboards, and setup documentation.

Changes

Jaeger v1 integration

Layer / File(s) Summary
Plugin contract and connection setup
plugins/Jaeger/v1/metadata.json, plugins/Jaeger/v1/ui.json, plugins/Jaeger/v1/configValidation.json, plugins/Jaeger/v1/custom_types.json, plugins/Jaeger/v1/indexDefinitions/default.json, plugins/Jaeger/v1/cspell.json, plugins/Jaeger/v1/docs/README.md
Defines Jaeger metadata, WebAPI connection fields, connection validation, Service and Dependency types, index mappings, spelling terms, and setup documentation.
Service and dependency streams
plugins/Jaeger/v1/dataStreams/services.json, plugins/Jaeger/v1/dataStreams/dependencies.json
Retrieves services from /api/v3/services and dependencies from /api/dependencies. The streams map service, parent, child, call count, and dependency label fields.
Operations and trace streams
plugins/Jaeger/v1/dataStreams/operations.json, plugins/Jaeger/v1/dataStreams/traces.json, plugins/Jaeger/v1/dataStreams/scripts/traces.js
Retrieves service operations and traces. The trace script converts OTLP JSON spans into flattened records with identifiers, timing, duration, status, service metadata, and attributes.
Scopes and dashboards
plugins/Jaeger/v1/defaultContent/scopes.json, plugins/Jaeger/v1/defaultContent/manifest.json, plugins/Jaeger/v1/defaultContent/overview.dash.json, plugins/Jaeger/v1/defaultContent/service.dash.json
Adds a single-service scope, overview and service dashboard entries, service and dependency visualizations, and service-scoped operations and traces tiles.

Sequence Diagram(s)

sequenceDiagram
  participant ServiceScope
  participant TracesDataStream
  participant JaegerQueryAPI
  participant TracesScript
  ServiceScope->>TracesDataStream: provide service ID
  TracesDataStream->>JaegerQueryAPI: GET /api/v3/traces
  JaegerQueryAPI-->>TracesDataStream: return OTLP JSON
  TracesDataStream->>TracesScript: transform trace response
  TracesScript-->>TracesDataStream: return flattened records
Loading
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title identifies the Jaeger plugin and is related to the main change, although it does not state that a new plugin is being added.
Description check ✅ Passed The description clearly covers the plugin purpose, testing, limitations, configuration, dashboards, documentation, and checklist items.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@plugins/Jaeger/v1/dataStreams/dependencies.json`:
- Around line 20-28: Update the lookback fallback in the getArgs configuration
to 3600000 milliseconds when timeframe?.unixStart and timeframe?.unixEnd are
unavailable, while preserving the existing calculated duration for valid
timeframes.

In `@plugins/Jaeger/v1/docs/README.md`:
- Line 1: Start the README with a meaningful level-one Markdown heading
describing the Jaeger plugin or integration, then keep the existing introductory
description immediately after it.

In `@plugins/Jaeger/v1/indexDefinitions/default.json`:
- Around line 18-22: Update the dependencies index definition’s timeframe from
"none" to "last1hour" so dependency requests cover the full hourly schedule.
Leave the dependencies dataStream configuration unchanged.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI (base), Organization UI (inherited)

Review profile: ASSERTIVE

Plan: Pro

Run ID: 43e8a4a2-653b-4fa0-bb4c-8dc38d23481d

📥 Commits

Reviewing files that changed from the base of the PR and between 55b2cfc and 64c5a5d.

⛔ Files ignored due to path filters (1)
  • plugins/Jaeger/v1/icon.png is excluded by !**/*.png
📒 Files selected for processing (16)
  • plugins/Jaeger/v1/configValidation.json
  • plugins/Jaeger/v1/cspell.json
  • plugins/Jaeger/v1/custom_types.json
  • plugins/Jaeger/v1/dataStreams/dependencies.json
  • plugins/Jaeger/v1/dataStreams/operations.json
  • plugins/Jaeger/v1/dataStreams/scripts/traces.js
  • plugins/Jaeger/v1/dataStreams/services.json
  • plugins/Jaeger/v1/dataStreams/traces.json
  • plugins/Jaeger/v1/defaultContent/manifest.json
  • plugins/Jaeger/v1/defaultContent/overview.dash.json
  • plugins/Jaeger/v1/defaultContent/scopes.json
  • plugins/Jaeger/v1/defaultContent/service.dash.json
  • plugins/Jaeger/v1/docs/README.md
  • plugins/Jaeger/v1/indexDefinitions/default.json
  • plugins/Jaeger/v1/metadata.json
  • plugins/Jaeger/v1/ui.json

Comment on lines +20 to +28
"getArgs": [
{
"key": "endTs",
"value": "{{timeframe?.unixEnd ? timeframe.unixEnd * 1000 : Date.now()}}"
},
{
"key": "lookback",
"value": "{{(timeframe?.unixStart && timeframe?.unixEnd) ? (timeframe.unixEnd - timeframe.unixStart) * 1000 : 1800000}}"
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Use the documented one-hour fallback.

When no timeframe exists, Line 27 sends a lookback of 1800000 ms. This selects 30 minutes. The README states that scheduled dependency indexing uses a one-hour trailing window.

Set the fallback to 3600000. Otherwise, scheduled imports omit dependency calls from half of the documented query window.

Proposed fix
-                "value": "{{(timeframe?.unixStart && timeframe?.unixEnd) ? (timeframe.unixEnd - timeframe.unixStart) * 1000 : 1800000}}"
+                "value": "{{(timeframe?.unixStart && timeframe?.unixEnd) ? (timeframe.unixEnd - timeframe.unixStart) * 1000 : 3600000}}"
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
"getArgs": [
{
"key": "endTs",
"value": "{{timeframe?.unixEnd ? timeframe.unixEnd * 1000 : Date.now()}}"
},
{
"key": "lookback",
"value": "{{(timeframe?.unixStart && timeframe?.unixEnd) ? (timeframe.unixEnd - timeframe.unixStart) * 1000 : 1800000}}"
}
"getArgs": [
{
"key": "endTs",
"value": "{{timeframe?.unixEnd ? timeframe.unixEnd * 1000 : Date.now()}}"
},
{
"key": "lookback",
"value": "{{(timeframe?.unixStart && timeframe?.unixEnd) ? (timeframe.unixEnd - timeframe.unixStart) * 1000 : 3600000}}"
}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@plugins/Jaeger/v1/dataStreams/dependencies.json` around lines 20 - 28, Update
the lookback fallback in the getArgs configuration to 3600000 milliseconds when
timeframe?.unixStart and timeframe?.unixEnd are unavailable, while preserving
the existing calculated duration for valid timeframes.

Comment thread plugins/Jaeger/v1/docs/README.md
Comment on lines +18 to +22
"name": "dependencies",
"dataStream": {
"name": "dependencies"
},
"timeframe": "none",

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Use the one-hour dependency timeframe.

"timeframe": "none" causes the dependencies request to use its 30-minute fallback lookback. An hourly index schedule then leaves a 30-minute gap between runs. Use last1hour, which the dependency stream supports.

Proposed fix
-            "timeframe": "none",
+            "timeframe": "last1hour",
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@plugins/Jaeger/v1/indexDefinitions/default.json` around lines 18 - 22, Update
the dependencies index definition’s timeframe from "none" to "last1hour" so
dependency requests cover the full hourly schedule. Leave the dependencies
dataStream configuration unchanged.

@coderabbitai

coderabbitai Bot commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

Note

GitHub couldn't provide a complete incremental comparison for this pull request, so CodeRabbit is performing a full review instead. This review may take a little longer.

@github-actions

github-actions Bot commented Aug 7, 2026

Copy link
Copy Markdown

🧩 Plugin PR Summary

📦 Modified Plugins

  • plugins/Jaeger/v1

📋 Results

Step Status
Validation ✅ Passed
Deployment 🚀 Deployed

🔍 Validation Details

jaeger
{
  "valid": true,
  "pluginName": "jaeger",
  "pluginType": "hybrid",
  "summary": {
    "Data Streams": 4,
    "Import Definitions": 1,
    "Correlation Rules": 0,
    "UI Configuration": true,
    "Has Icon": true,
    "Has Default Content": true,
    "Config Validation": true,
    "Custom Types": true
  }
}

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@plugins/Jaeger/v1/dataStreams/scripts/traces.js`:
- Around line 27-36: Update attrsToObject to recursively convert every OTLP
AnyValue variant, including bytesValue, arrayValue elements, and kvlistValue
entries, while preserving existing scalar conversions. Ensure non-scalar values
remain present and correctly nested in serialized attributes, and add fixtures
covering each non-scalar variant.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI (base), Organization UI (inherited)

Review profile: ASSERTIVE

Plan: Pro

Run ID: 4732ac9b-05c6-4a3a-bf2b-e890fb6deafd

📥 Commits

Reviewing files that changed from the base of the PR and between 3d1deba and 504d387.

⛔ Files ignored due to path filters (1)
  • plugins/Jaeger/v1/icon.png is excluded by !**/*.png
📒 Files selected for processing (16)
  • plugins/Jaeger/v1/configValidation.json
  • plugins/Jaeger/v1/cspell.json
  • plugins/Jaeger/v1/custom_types.json
  • plugins/Jaeger/v1/dataStreams/dependencies.json
  • plugins/Jaeger/v1/dataStreams/operations.json
  • plugins/Jaeger/v1/dataStreams/scripts/traces.js
  • plugins/Jaeger/v1/dataStreams/services.json
  • plugins/Jaeger/v1/dataStreams/traces.json
  • plugins/Jaeger/v1/defaultContent/manifest.json
  • plugins/Jaeger/v1/defaultContent/overview.dash.json
  • plugins/Jaeger/v1/defaultContent/scopes.json
  • plugins/Jaeger/v1/defaultContent/service.dash.json
  • plugins/Jaeger/v1/docs/README.md
  • plugins/Jaeger/v1/indexDefinitions/default.json
  • plugins/Jaeger/v1/metadata.json
  • plugins/Jaeger/v1/ui.json

Comment on lines +27 to +36
function attrsToObject(attributes) {
const obj = {};
(attributes || []).forEach((a) => {
const value = a.value || {};
obj[a.key] =
value.stringValue ??
value.intValue ??
value.doubleValue ??
value.boolValue;
});

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -eu

file="plugins/Jaeger/v1/dataStreams/scripts/traces.js"
printf '%s\n' "== target file =="
cat -n "$file" | sed -n '1,140p'

printf '%s\n' "== related Jaeger data-stream files =="
git ls-files 'plugins/Jaeger/v1/dataStreams/*' | sed -n '1,160p'

printf '%s\n' "== attrsToObject usages and attribute fixtures =="
rg -n -S 'attrsToObject|attributes|bytesValue|arrayValue|kvlistValue|intValue|doubleValue|boolValue' \
  plugins/Jaeger/v1/dataStreams plugins/Jaeger/v1 2>/dev/null | sed -n '1,240p'

Repository: squaredup/plugins

Length of output: 5749


🏁 Script executed:

#!/bin/bash
set -eu

printf '%s\n' "== traces data-stream schema around attributes =="
cat -n plugins/Jaeger/v1/dataStreams/traces.json | sed -n '80,125p'

printf '%s\n' "== plugin metadata and version references =="
fd -i 'metadata.json' plugins/Jaeger | while read -r f; do
    printf '\n%s\n' "[$f]"
    cat -n "$f" | sed -n '1,100p'
done

printf '%s\n' "== standalone behavior probe =="
node - <<'JS'
function attrsToObject(attributes) {
    const obj = {};
    (attributes || []).forEach((a) => {
        const value = a.value || {};
        obj[a.key] =
            value.stringValue ??
            value.intValue ??
            value.doubleValue ??
            value.boolValue;
    });
    return obj;
}

const input = [
    { key: "bytes", value: { bytesValue: "AQI=" } },
    {
        key: "array",
        value: { arrayValue: { values: [
            { stringValue: "x" },
            { intValue: "7" }
        ] } }
    },
    {
        key: "map",
        value: { kvlistValue: { values: [
            { key: "nested", value: { boolValue: true } }
        ] } }
    }
];

const output = attrsToObject(input);
console.log("object:", JSON.stringify(output));
console.log("bytes:", output.bytes);
console.log("array:", output.array);
console.log("map:", output.map);
console.log("serialized:", JSON.stringify({ attributes: output }));
JS

Repository: squaredup/plugins

Length of output: 3210


🏁 Script executed:

#!/bin/bash
set -eu

printf '%s\n' "== changed files =="
git diff --name-only

printf '%s\n' "== change summary =="
git diff --stat

printf '%s\n' "== metadata change, if any =="
git diff -- plugins/Jaeger/v1/metadata.json

Repository: squaredup/plugins

Length of output: 226


Preserve non-scalar OTLP attributes.

attrsToObject handles only scalar AnyValue variants. Valid bytesValue, arrayValue, and kvlistValue attributes become undefined, so JSON serialization omits them from the attributes field. Implement a recursive AnyValue converter and add fixtures for each non-scalar variant.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@plugins/Jaeger/v1/dataStreams/scripts/traces.js` around lines 27 - 36, Update
attrsToObject to recursively convert every OTLP AnyValue variant, including
bytesValue, arrayValue elements, and kvlistValue entries, while preserving
existing scalar conversions. Ensure non-scalar values remain present and
correctly nested in serialized attributes, and add fixtures covering each
non-scalar variant.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

new-plugin Used to PR newly added plugins

Development

Successfully merging this pull request may close these issues.

2 participants