Skip to content

Instantly share code, notes, and snippets.

@juampi92
Created September 18, 2025 10:23
Show Gist options
  • Select an option

  • Save juampi92/898df98e1724acb802358d6ecc059141 to your computer and use it in GitHub Desktop.

Select an option

Save juampi92/898df98e1724acb802358d6ecc059141 to your computer and use it in GitHub Desktop.
A bash script that generates W3C traceparent headers for testing, waits while you use the traceparent in your tests, then sends the completed trace span to Jaeger using OTLP Http..
#!/bin/bash
# Traceparent Generator and Jaeger Trace Sender
#
# This script generates a W3C traceparent header, allows time to copy it,
# and then sends a corresponding trace span to Jaeger via OpenTelemetry HTTP protocol.
#
# Requirements: curl (usually pre-installed on macOS/Linux)
#
# Usage:
# - Run: ./otel_trace_generator.sh
# - Copy the generated traceparent header when displayed
# - Press Enter when ready to close the span and send to Jaeger
#
# Help:
# - Run: ./otel_trace_generator.sh --help
set -e # Exit on error
# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
CYAN='\033[0;36m'
NC='\033[0m' # No Color
# Default configuration
DEFAULT_JAEGER_PORT=4318
# Function to generate random hex string
generate_hex() {
local length=$1
openssl rand -hex $((length/2))
}
# Function to get current time in nanoseconds
get_time_ns() {
if [[ "$OSTYPE" == "darwin"* ]]; then
# macOS
python3 -c "import time; print(int(time.time() * 1000000000))"
else
# Linux
date +%s%N
fi
}
# Function to format timestamp for display (removed due to compatibility issues)
format_timestamp() {
echo "timestamp"
}
# Function to create OTLP trace JSON
create_trace_json() {
local trace_id=$1
local span_id=$2
local start_time_ns=$3
local end_time_ns=$4
local service_name=$5
cat <<EOF
{
"resourceSpans": [
{
"resource": {
"attributes": [
{
"key": "service.name",
"value": {"stringValue": "$service_name"}
},
{
"key": "service.version",
"value": {"stringValue": "1.0.0"}
}
]
},
"scopeSpans": [
{
"scope": {
"name": "trace-generator",
"version": "1.0.0"
},
"spans": [
{
"traceId": "$trace_id",
"spanId": "$span_id",
"name": "manual-trace-span",
"kind": 1,
"startTimeUnixNano": "$start_time_ns",
"endTimeUnixNano": "$end_time_ns",
"attributes": [
{
"key": "span.type",
"value": {"stringValue": "manual"}
},
{
"key": "generator.script",
"value": {"stringValue": "trace_generator.sh"}
}
],
"status": {
"code": 1
}
}
]
}
]
}
]
}
EOF
}
# Function to send trace to Jaeger
send_trace_to_jaeger() {
local json_data=$1
local jaeger_endpoint=$2
local response
local http_code
response=$(curl -s -w "\n%{http_code}" \
-X POST \
-H "Content-Type: application/json" \
-H "User-Agent: trace-generator-script/1.0.0" \
-d "$json_data" \
"$jaeger_endpoint" 2>/dev/null)
http_code=$(echo "$response" | tail -n1)
if [[ "$http_code" == "200" ]]; then
return 0
else
echo "HTTP $http_code: $(echo "$response" | head -n -1)"
return 1
fi
}
# Function to show usage
show_usage() {
echo "Usage: $0 [service-name] [--port=PORT]"
echo ""
echo "Arguments:"
echo " service-name Name of the service (default: trace-generator-script)"
echo ""
echo "Options:"
echo " --port=PORT Jaeger OTLP HTTP port (default: $DEFAULT_JAEGER_PORT)"
echo " --help Show this help message"
echo ""
echo "Examples:"
echo " $0 # Use defaults"
echo " $0 my-service # Use custom service name"
echo " $0 my-service --port=4318 # Custom name and port"
echo " $0 --port=14268 # Custom port, default name"
}
# Function to parse command line arguments
parse_arguments() {
local service_name="trace-generator-script"
local jaeger_port=$DEFAULT_JAEGER_PORT
while [[ $# -gt 0 ]]; do
case $1 in
--port=*)
jaeger_port="${1#*=}"
if ! [[ "$jaeger_port" =~ ^[0-9]+$ ]] || [[ "$jaeger_port" -lt 1 ]] || [[ "$jaeger_port" -gt 65535 ]]; then
echo -e "${RED}❌ Error: Invalid port number '$jaeger_port'. Must be between 1-65535.${NC}" >&2
exit 1
fi
shift
;;
--help|-h)
show_usage
exit 0
;;
--*)
echo -e "${RED}❌ Error: Unknown option '$1'${NC}" >&2
echo ""
show_usage
exit 1
;;
*)
# This is the service name (positional argument)
service_name="$1"
shift
;;
esac
done
echo "$service_name|$jaeger_port"
}
# Main script
main() {
local parsed_args=$(parse_arguments "$@")
local service_name="${parsed_args%|*}"
local jaeger_port="${parsed_args#*|}"
local jaeger_endpoint="http://localhost:${jaeger_port}/v1/traces"
echo -e "${BLUE}πŸ” Traceparent Generator & Jaeger Trace Sender${NC}"
echo "=================================================="
# Step 1: Generate traceparent header
local version="00"
local trace_id=$(generate_hex 32)
local span_id=$(generate_hex 16)
local trace_flags="01"
local traceparent="${version}-${trace_id}-${span_id}-${trace_flags}"
local start_time_ns=$(get_time_ns)
echo
echo -e "${YELLOW}πŸ“‹ Generated traceparent header:${NC}"
echo " $traceparent"
echo
echo -e "${CYAN}πŸ“Š Trace Details:${NC}"
echo " Service: $service_name"
echo " Trace ID: $trace_id"
echo " Span ID: $span_id"
echo
echo -e "${YELLOW}βœ‚οΈ Copy the traceparent header above if needed.${NC}"
echo -e "${YELLOW}⏳ Press Enter when ready to close the span and send to Jaeger...${NC}"
# Step 2: Wait for user input
read -r
# Step 3: Calculate duration and create trace data
local end_time_ns=$(get_time_ns)
local duration_ms=$(( (end_time_ns - start_time_ns) / 1000000 ))
echo
echo -e "${CYAN}⏱️ Span Duration: ${duration_ms} ms${NC}"
# Step 4: Create and send trace data
local trace_json=$(create_trace_json "$trace_id" "$span_id" "$start_time_ns" "$end_time_ns" "$service_name")
echo
echo -e "${BLUE}πŸš€ Sending trace to Jaeger (port ${jaeger_port})...${NC}"
if send_trace_to_jaeger "$trace_json" "$jaeger_endpoint"; then
echo -e "${GREEN}βœ… Trace successfully sent to Jaeger!${NC}"
echo
echo -e "${CYAN}πŸ”— View in Jaeger UI:${NC}"
echo " http://localhost:16686/trace/$trace_id"
else
echo -e "${RED}❌ Failed to send trace to Jaeger${NC}"
echo
echo -e "${YELLOW}πŸ’‘ Make sure Jaeger is running with OTLP HTTP receiver on port ${jaeger_port}${NC}"
echo " Docker: docker run -p 16686:16686 -p ${jaeger_port}:4318 jaegertracing/all-in-one:latest"
exit 1
fi
}
# Handle Ctrl+C gracefully
trap 'echo -e "\n\n${RED}❌ Operation cancelled by user.${NC}"; exit 0' INT
# Run main function
main "$@"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment