Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions hack/upload-traces-otelcol-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,12 @@ receivers:
exporters:
otlphttp:
endpoint: "${env:REPLAY_ENDPOINT}"
# Add headers below. otelcol-contrib ignores the OTEL_EXPORTER_OTLP_HEADERS
# env var; headers must be set here in the YAML config.
#
# headers:
# Authorization: "Bearer mytoken"
# x-mlflow-experiment-id: "42"

service:
pipelines:
Expand Down
55 changes: 30 additions & 25 deletions hack/upload-traces.sh
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,13 @@
set -euo pipefail

SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
CONFIG_TEMPLATE="${SCRIPT_DIR}/upload-traces-otelcol-config.yaml"
CONFIG="${SCRIPT_DIR}/upload-traces-otelcol-config.yaml"

die() { echo "error: $*" >&2; exit 1; }

usage() {
cat <<EOF
Usage: $(basename "$0") <file-or-dir-or-glob> --endpoint <otlp-http-url> [--header key=value]...
Usage: $(basename "$0") <file-or-dir-or-glob> --endpoint <otlp-http-url>

Replay OTLP JSON traces into an OTLP HTTP endpoint.

Expand All @@ -18,14 +18,19 @@ pushes them to any OTLP-speaking backend via otelcol-contrib.
Arguments:
<file-or-dir-or-glob> A .jsonl file, directory, or glob pattern
--endpoint OTLP HTTP endpoint (e.g. http://localhost:4318)
--header key=value Header to send with OTLP requests (repeatable)

Headers are passed via the OTEL_EXPORTER_OTLP_HEADERS env var. Any value
already set in the environment is preserved and appended to.
To send headers (auth tokens, experiment IDs, etc.), edit the config file
directly — otelcol-contrib reads headers from its YAML config, not from
env vars or CLI flags:

$CONFIG

If yq is installed and no headers are configured, the script prompts for
confirmation before sending traces without authentication.

Examples:
$(basename "$0") run/agent-run-123/run-telemetry.jsonl --endpoint http://localhost:4318
$(basename "$0") run/ --endpoint http://localhost:4318 --header x-mlflow-experiment-id=42
$(basename "$0") run/ --endpoint http://localhost:4318
$(basename "$0") 'run/*/run-telemetry.jsonl' --endpoint http://localhost:4318

The collector runs continuously and watches for new data. This is useful
Expand All @@ -42,18 +47,12 @@ EOF
# --- parse args ---
SOURCE=""
ENDPOINT=""
HEADERS=""

while [[ $# -gt 0 ]]; do
case "$1" in
--endpoint)
[[ $# -ge 2 ]] || die "--endpoint requires a value"
ENDPOINT="$2"; shift 2 ;;
--header)
[[ $# -ge 2 ]] || die "--header requires a key=value"
[[ "$2" == *=* ]] || die "--header value must be key=value, got: $2"
if [[ -n "$HEADERS" ]]; then HEADERS="${HEADERS},$2"; else HEADERS="$2"; fi
shift 2 ;;
--help|-h)
usage ;;
-*)
Expand All @@ -71,16 +70,15 @@ done
command -v otelcol-contrib >/dev/null 2>&1 \
|| die "otelcol-contrib not found. Install: https://github.com/open-telemetry/opentelemetry-collector-releases/releases"

[[ -f "$CONFIG_TEMPLATE" ]] \
|| die "config template not found: $CONFIG_TEMPLATE"
[[ -f "$CONFIG" ]] \
|| die "config not found: $CONFIG"

# --- resolve to absolute include pattern ---
if [[ -d "$SOURCE" ]]; then
INCLUDE="$(cd "$SOURCE" && pwd)/**/*.jsonl"
elif [[ -f "$SOURCE" ]]; then
INCLUDE="$(cd "$(dirname "$SOURCE")" && pwd)/$(basename "$SOURCE")"
else
# Treat as a glob pattern — make it absolute relative to cwd
if [[ "$SOURCE" == /* ]]; then
INCLUDE="$SOURCE"
else
Expand All @@ -90,18 +88,25 @@ fi
echo "include: $INCLUDE"

# --- run collector ---
export REPLAY_INCLUDE="$INCLUDE"
export REPLAY_ENDPOINT="$ENDPOINT"

# Merge --header flags with any existing OTEL_EXPORTER_OTLP_HEADERS.
if [[ -n "$HEADERS" ]]; then
if [[ -n "${OTEL_EXPORTER_OTLP_HEADERS:-}" ]]; then
export OTEL_EXPORTER_OTLP_HEADERS="${OTEL_EXPORTER_OTLP_HEADERS},${HEADERS}"
else
export OTEL_EXPORTER_OTLP_HEADERS="$HEADERS"
# confmap recursively expands ${scheme:...} tokens in resolved values.
# Escape literal $ as $$ so paths/URLs can't pivot into env var lookups.
escape_confmap() { printf '%s' "${1//\$/\$\$}"; }

REPLAY_INCLUDE="$(escape_confmap "$INCLUDE")"
export REPLAY_INCLUDE
REPLAY_ENDPOINT="$(escape_confmap "$ENDPOINT")"
export REPLAY_ENDPOINT

if command -v yq >/dev/null 2>&1; then
header_count="$(yq '.exporters.otlphttp.headers | length' "$CONFIG" 2>/dev/null || echo 0)"
if [[ "$header_count" -eq 0 ]]; then
echo "warning: no headers configured in $CONFIG"
echo "traces will be sent without authentication headers."
read -rp "Continue? [y/N] " answer
[[ "$answer" =~ ^[Yy]$ ]] || exit 0
fi
fi

echo "endpoint: $ENDPOINT"
echo "starting otelcol-contrib (runs continuously, watching for new data; press Ctrl+C to stop)..."
otelcol-contrib --config "$CONFIG_TEMPLATE"
otelcol-contrib --config "$CONFIG"
Loading