{"id":48099021,"url":"https://github.com/jimschubert/otel-relay","last_synced_at":"2026-04-04T15:40:32.475Z","repository":{"id":338837179,"uuid":"1159392927","full_name":"jimschubert/otel-relay","owner":"jimschubert","description":"A toy project for local evaluation of OpenTelemetry signals, outside the scope of a local collector","archived":false,"fork":false,"pushed_at":"2026-03-02T23:22:08.000Z","size":95,"stargazers_count":1,"open_issues_count":6,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-03-09T11:52:22.114Z","etag":null,"topics":["go","golang","opentelemetry","otel"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/jimschubert.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-02-16T17:14:25.000Z","updated_at":"2026-02-24T12:35:45.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/jimschubert/otel-relay","commit_stats":null,"previous_names":["jimschubert/otel-relay"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/jimschubert/otel-relay","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jimschubert%2Fotel-relay","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jimschubert%2Fotel-relay/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jimschubert%2Fotel-relay/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jimschubert%2Fotel-relay/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/jimschubert","download_url":"https://codeload.github.com/jimschubert/otel-relay/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jimschubert%2Fotel-relay/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31403960,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-04T10:20:44.708Z","status":"ssl_error","status_checked_at":"2026-04-04T10:20:06.846Z","response_time":60,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["go","golang","opentelemetry","otel"],"created_at":"2026-04-04T15:40:32.368Z","updated_at":"2026-04-04T15:40:32.461Z","avatar_url":"https://github.com/jimschubert.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# OTel Relay\n\n[![Build Status](https://github.com/jimschubert/otel-relay/actions/workflows/build.yml/badge.svg)](https://github.com/jimschubert/otel-relay/actions/workflows/build.yml)\n[![Go Version](https://img.shields.io/github/go-mod/go-version/jimschubert/otel-relay)](https://github.com/jimschubert/otel-relay/blob/main/go.mod)\n[![License](https://img.shields.io/github/license/jimschubert/otel-relay?a=b\u0026color=blue)](https://github.com/jimschubert/otel-relay/blob/main/LICENSE)\n[![Go Report Card](https://goreportcard.com/badge/github.com/jimschubert/otel-relay)](https://goreportcard.com/report/github.com/jimschubert/otel-relay)\n[![GitHub Release](https://img.shields.io/github/v/release/jimschubert/otel-relay)](https://github.com/jimschubert/otel-relay/releases/latest)\n\nA language-agnostic transparent proxy for debugging/viewing OpenTelemetry signals; not intended for production use.\n\n```\n📊 TRACE\n├─ Resource:\n│  ├─ service.name: my-service\n│  ├─ service.version: 1.0.0\n├─ 🔗 Span: database-query\n│  ├─ Duration: 45.2ms\n│  ├─ db.system: postgresql\n│  └─ db.statement: SELECT * FROM users\n```\n\nWhy would you use this?\n\n1. You're just getting started and want to see what signals are being emitted to your collector, but don't want to\n   configure a \"real\" collector.\n2. You wanna see what attributes are actually being sent.\n3. You want to see if your instrumentation is working at all, but you're not ready to emit them _somewhere_ (maybe\n   verbose logging in the collector doesn't give you what you want).\n\nWhat are some issues with just using otel-collector?\n\n1. OTel Collector supports SIGHUP for reload (see [PR](https://github.com/open-telemetry/opentelemetry-collector/pull/6000)), but this will reload _everything_. There's no way to reload just OTLP receivers.\n2. Any logging/debugging is mixed into other pipelines, which allows human error to misconfigure the collector on reload ([this blog](https://last9.io/blog/hot-reload-for-opentelemetry-collector/) has it right: \"Always, and I mean ALWAYS, validate your config changes before reloading.\").\n3. It's designed for multiple exporters, usually signal-specific or target an external or system-wide sink which is not ideal for ad hoc debugging. Many useful exporters are in [opentelemetry-collector-contrib](https://github.com/open-telemetry/opentelemetry-collector-contrib/tree/HEAD/exporter), adding complexity to the setup.\n4. Enabling ad hoc evaluation of a single service on a system with mulitiple running services could get tricky.\n\n\u003e [!NOTE]\n\u003e This is not meant to replace the collector.\n\u003e You can setup either in front of the collector or as a separate exporter in the collector.\n\n## Installation\n\n```bash\ngo install github.com/jimschubert/otel-relay/cmd@latest\n```\n\nOr build from source:\n\n```bash\ngit clone https://github.com/jimschubert/otel-relay\ncd otel-relay\ngo build -o otel-relay cmd/otel-relay/main.go\n```\n\n## Usage\n\nStart the proxy server:\n\n```bash\notel-relay\n```\n\nPoint your app to `localhost:14317` (note the port starts with a `1`). You'll see telemetry data in real-time.\n\nTo forward to an actual collector (note the port _does not_ start with a `1` here):\n\n```bash\notel-relay --upstream localhost:4317\n```\n\nEmit telemetry to a Unix domain socket for inspection:\n\n```bash\notel-relay --socket /tmp/otel-relay.sock --emit\n```\n\nChange the listening port:\n\n```bash\notel-relay --listen :9999\n```\n\n## Configuration\n\nThe relay is configured via command-line flags:\n\n```\n-l, --listen=\":14317\"                    Address to listen on for OTLP gRPC\n-u, --upstream=\u003chost:port\u003e               Upstream OTLP collector address (optional)\n-L, --listen-http=\u003cport\u003e                 Address to listen on for HTTP/JSON (optional)\n-U, --upstream-http=\u003cscheme:host:port\u003e   Upstream HTTP collector URL (optional)\n-s, --socket=\"/tmp/otel-relay.sock\"      Path to Unix domain socket for gRPC inspector service (optional)\n    --[no-]emit                          Whether to emit signals to unix socket (default: true)\n    --[no-]relay-metrics                 Whether to emit this tooling's own metrics (default: true)\n    --relay-metrics-backend              OTLP endpoint to push metrics to (default: same as --upstream/-u if set, otherwise localhost:4317)\n```\n\n## OS Signals\n\nThe relay supports the following OS signals:\n- `SIGINT` and `SIGTERM`: Gracefully shut down the server.\n\n## Inspector Tool\n\nThe `otel-inspector` CLI connects to the relay's gRPC socket to view telemetry:\n\n```bash\ngo build -o otel-inspector cmd/otel-inspector/main.go\n./otel-inspector --socket /tmp/otel-relay.sock\n```\n\nInteractive commands (when keyboard input is available):\n- `v`: Toggle verbose mode (show all attributes vs limited)\n- `s`: Check daemon stats (no. of signals processed, bytes processed, uptime)\n- `q`: Quit\n\nOptions:\n```\n-s, --socket=\"/tmp/otel-relay.sock\"  Path to Unix domain socket\n-f, --format=\"tree\"                   Output format (tree, json)\n-v, --verbose                         Verbose output (show all attributes)\n```\n\n## Examples\n\n### Local Example\n\nThere's a working example in the `cmd/example/` directory. See [cmd/example/README.md](cmd/example/README.md).\n\n### OpenTelemetry Full Demo\n\nYou can also check this out with the [OpenTelemetry Full Demo](https://opentelemetry.io/docs/demo/docker-deployment/), it just requires a little modification.\nThe demo can run with Docker or Kubernetes, but we'll use Docker for this example's instructions.\n\n**1. Set ENV Overrides**\nIn `.env.override`, add the following to match the ports used by `otel-relay`:\n\n```\nOTEL_COLLECTOR_HOST=host.docker.internal\nOTEL_COLLECTOR_PORT_GRPC=14317\nOTEL_COLLECTOR_PORT_HTTP=14318\n```\n\nThe `host.docker.internal` is a special DNS name in default docker networks. If this doesn't work for you, I'm assuming you know how to modify it.\n\n**2. Modify docker-compose.yml**\nIn `docker-compose.yml`, remove these environment mappings from the `otel-collector` service:\n\n```\n- OTEL_COLLECTOR_HOST\n- OTEL_COLLECTOR_PORT_GRPC\n- OTEL_COLLECTOR_PORT_HTTP\n```\n\nAnd replace the `otel-collector` service's port mappings with the following to map to the host ports:\n\n```\n- \"4317:4317\"\n- \"4318:4318\"\n```\n\n**3. Modify otel-collector config**\n\nIn `src/otel-collector/otelcol-config.yml`, find and replace:\n* `${env:OTEL_COLLECTOR_HOST}` with `otel-collector`\n* `${env:OTEL_COLLECTOR_PORT_GRPC}` with `4317`\n* `${env:OTEL_COLLECTOR_PORT_HTTP}` with `4318`\n\n**4. Start the demo**\n\n```bash\nmake start # NOTE be sure to `make stop` when you're done.\n````\n\n**The result**\n\nAll services will emit to your locally running `otel-relay` instead of the compose environment's otel-collector.\nThe local `otel-relay` will forward to the collector as well, so you can see the full demo in action.\n\n**Start otel-relay**\n\n```bash\n./otel-relay --listen=\":14317\" \\\n             --upstream=localhost:4317 \\\n             --listen-http=\":14318\" \\\n             --upstream-http=\"http://localhost:4318\" \\\n             --emit\n```\nThis enables both the HTTP and gRPC forwarders, emitting telemetry to the socket for inspection.\nYou can adjust these flags as needed. For example:\n\n* Disable the local socket: change `--emit` to `--no-emit`\n\n## Acknowledgements\n\nI was inspired after mentioning [Expedia's Haystack](https://github.com/ExpediaDotCom/haystack) to someone.\nI used to work at Expedia and I _loved_ Haystack. We use OpenTelemetry where I work now, and its architecture is a lot \nlike Haystack's. However, Haystack's stream-first design meant you could \"attach\" viewers without ever needing to \nrecompile core components or stop/start processing. I wanted something like that for OpenTelemetry, and this will aim to be that option.\n\nI took additional inspirate from the OTel collector's [debugexporter](https://github.com/open-telemetry/opentelemetry-collector/tree/main/exporter/debugexporter).\nThe initial intent of this project is to have a streaming view of OTel signals, so you can \"peek\" at the traffic locally.\n\n## License\n\nApache 2.0 - see [LICENSE](LICENSE)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjimschubert%2Fotel-relay","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjimschubert%2Fotel-relay","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjimschubert%2Fotel-relay/lists"}