{"id":13582001,"url":"https://github.com/equinix-labs/otel-cli","last_synced_at":"2025-05-14T13:06:16.973Z","repository":{"id":37246417,"uuid":"328012280","full_name":"equinix-labs/otel-cli","owner":"equinix-labs","description":"OpenTelemetry command-line tool for sending events from shell scripts \u0026 similar environments","archived":false,"fork":false,"pushed_at":"2025-05-12T22:46:41.000Z","size":637,"stargazers_count":599,"open_issues_count":40,"forks_count":57,"subscribers_count":14,"default_branch":"main","last_synced_at":"2025-05-12T23:33:07.388Z","etag":null,"topics":["cli","observability","opentelemetry","shell"],"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/equinix-labs.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","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}},"created_at":"2021-01-08T21:05:52.000Z","updated_at":"2025-05-06T11:49:03.000Z","dependencies_parsed_at":"2023-02-18T08:45:41.369Z","dependency_job_id":"26e57899-c354-4746-a5af-065a023bb32b","html_url":"https://github.com/equinix-labs/otel-cli","commit_stats":{"total_commits":195,"total_committers":32,"mean_commits":6.09375,"dds":0.6512820512820513,"last_synced_commit":"3a5648dd799fcb430275a1c139e01b30f4ba22ef"},"previous_names":["packethost/otel-cli"],"tags_count":27,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/equinix-labs%2Fotel-cli","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/equinix-labs%2Fotel-cli/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/equinix-labs%2Fotel-cli/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/equinix-labs%2Fotel-cli/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/equinix-labs","download_url":"https://codeload.github.com/equinix-labs/otel-cli/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":253843168,"owners_count":21972867,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","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":["cli","observability","opentelemetry","shell"],"created_at":"2024-08-01T15:02:22.579Z","updated_at":"2025-05-14T13:06:16.932Z","avatar_url":"https://github.com/equinix-labs.png","language":"Go","funding_links":[],"categories":["Go","Uncategorized"],"sub_categories":["Uncategorized"],"readme":"# otel-cli\n\n[![](https://img.shields.io/badge/stability-experimental-lightgrey.svg)](https://github.com/packethost/standards/blob/master/experimental-statement.md)\n\notel-cli is a command-line tool for sending OpenTelemetry traces. It is written in\nGo and intended to be used in shell scripts and other places where the best option\navailable for sending spans is executing another program.\n\notel-cli can be added to your scripts with no configuration and it will run as normal\nbut in non-recording mode and will emit no traces. This follows the OpenTelemetry community's\nphilosophy of \"first, do no harm\" and makes it so you can add otel-cli to your code and\nlater turn it on.\n\nSince otel-cli needs to connect to the OTLP endpoint on each run, it is highly recommended\nto use a localhost opentelemetry collector that can buffer spans so that the connection\ncost does not slow down your program too much.\n\n## Getting Started\n\nWe publish a number of package formats for otel-cli, including tar.gz, zip (windows),\napk (Alpine), rpm (Red Hat variants), deb (Debian variants), and a brew tap. These\ncan be found on the repo's [Releases](https://github.com/equinix-labs/otel-cli/releases) page.\n\nOn most platforms the easiest way is a go get:\n\n```shell\ngo install github.com/equinix-labs/otel-cli@latest\n```\n\nDocker images are published for each otel-cli release as well:\n\n```shell\ndocker pull ghcr.io/equinix-labs/otel-cli:latest\ndocker run ghcr.io/equinix-labs/otel-cli:latest status\n```\n\nTo use the brew tap e.g. on MacOS:\n\n```shell\nbrew tap equinix-labs/otel-cli\nbrew install otel-cli\n```\n\nAlternatively, clone the repo and build it locally:\n\n```shell\ngit clone git@github.com:equinix-labs/otel-cli.git\ncd otel-cli\ngo build\n```\n\n## Examples\n\n```shell\n# run otel-cli as a local OTLP server and print traces to your console\n# run this in its own terminal and try some of the commands below!\notel-cli server tui\n\n# configure otel-cli to talk the the local server spawned above\nexport OTEL_EXPORTER_OTLP_ENDPOINT=localhost:4317\n\n# run a program inside a span\notel-cli exec --service my-service --name \"curl google\" curl https://google.com\n\n# otel-cli propagates context via envvars so you can chain it to create child spans\notel-cli exec --kind producer -- otel-cli exec --kind consumer sleep 1\n\n# if a traceparent envvar is set it will be automatically picked up and\n# used by span and exec. use --tp-ignore-env to ignore it even when present\nexport TRACEPARENT=00-0af7651916cd43dd8448eb211c80319c-b7ad6b7169203331-01\n\n# you can pass the traceparent to a child via arguments as well\n# {{traceparent}} in any of the command's arguments will be replaced with the traceparent string\notel-cli exec --name \"curl api\" -- \\\n   curl -H 'traceparent: {{traceparent}}' https://myapi.com/v1/coolstuff\n\n# create a span with a custom start/end time using either RFC3339,\n# same with the nanosecond extension, or Unix epoch, with/without nanos\notel-cli span --start 2021-03-24T07:28:05.12345Z --end 2021-03-24T07:30:08.0001Z\notel-cli span --start 1616620946 --end 1616620950.241980634\n# so you can do this:\nstart=$(date --rfc-3339=ns) # rfc3339 with nanoseconds\nsome-interesting-program --with-some-options\nend=$(date +%s.%N) # Unix epoch with nanoseconds\notel-cli span -n my-script -s some-interesting-program --start $start --end $end\n\n# for advanced cases you can start a span in the background, and\n# add events to it, finally closing it later in your script\nsockdir=$(mktemp -d)\notel-cli span background \\\n   --service $0          \\\n   --name \"$0 runtime\"   \\\n   --sockdir $sockdir \u0026 # the \u0026 is important here, background server will block\nsleep 0.1 # give the background server just a few ms to start up\notel-cli span event --name \"cool thing\" --attrs \"foo=bar\" --sockdir $sockdir\notel-cli span end --sockdir $sockdir\n# or you can kill the background process and it will end the span cleanly\nkill %1\n\n# server mode can also write traces to the filesystem, e.g. for testing\ndir=$(mktemp -d)\notel-cli server json --dir $dir --timeout 60 --max-spans 5\n```\n\n## Configuration\n\nEverything is configurable via CLI arguments, json config, and environment\nvariables. If no endpoint is specified, otel-cli will run in non-recording\nmode and not attempt to contact any servers.\n\nAll three modes of config can be mixed. Command line args are loaded first,\nthen config file, then environment variables.\n\n| CLI argument         | environment variable                  | config file key          | example value  |\n| -------------------- | ------------------------------------- | ------------------------ | -------------- |\n| --endpoint           | OTEL_EXPORTER_OTLP_ENDPOINT           | endpoint                 | localhost:4317       |\n| --traces-endpoint    | OTEL_EXPORTER_OTLP_TRACES_ENDPOINT    | traces_endpoint          | https://localhost:4318/v1/traces |\n| --protocol           | OTEL_EXPORTER_OTLP_PROTOCOL           | protocol                 | http/protobuf  |\n| --insecure           | OTEL_EXPORTER_OTLP_INSECURE           | insecure                 | false          |\n| --timeout            | OTEL_EXPORTER_OTLP_TIMEOUT            | timeout                  | 1s             |\n| --otlp-headers       | OTEL_EXPORTER_OTLP_HEADERS            | otlp_headers             | k=v,a=b        |\n| --otlp-blocking      | OTEL_EXPORTER_OTLP_BLOCKING           | otlp_blocking            | false          |\n| --config             | OTEL_CLI_CONFIG_FILE                  | config_file              | config.json    |\n| --verbose            | OTEL_CLI_VERBOSE                      | verbose                  | false          |\n| --fail               | OTEL_CLI_FAIL                         | fail                     | false          |\n| --service            | OTEL_SERVICE_NAME                     | service_name             | myapp          |\n| --kind               | OTEL_CLI_TRACE_KIND                   | span_kind                | server         |\n| --status-code        | OTEL_CLI_STATUS_CODE                  | span_status_code         | error          |\n| --status-description | OTEL_CLI_STATUS_DESCRIPTION           | span_status_description  | cancelled      |\n| --attrs              | OTEL_CLI_ATTRIBUTES                   | span_attributes          | k=v,a=b        |\n| --force-trace-id     | OTEL_CLI_FORCE_TRACE_ID               | force_trace_id           | 00112233445566778899aabbccddeeff |\n| --force-span-id      | OTEL_CLI_FORCE_SPAN_ID                | force_span_id            | beefcafefacedead |\n| --force-parent-span-id | OTEL_CLI_FORCE_PARENT_SPAN_ID       | force_parent_span_id     | eeeeeeb33fc4f3d3 |\n| --tp-required        | OTEL_CLI_TRACEPARENT_REQUIRED         | traceparent_required     | false          |\n| --tp-carrier         | OTEL_CLI_CARRIER_FILE                 | traceparent_carrier_file | filename.txt   |\n| --tp-ignore-env      | OTEL_CLI_IGNORE_ENV                   | traceparent_ignore_env   | false          |\n| --tp-print           | OTEL_CLI_PRINT_TRACEPARENT            | traceparent_print        | false          |\n| --tp-export          | OTEL_CLI_EXPORT_TRACEPARENT           | traceparent_print_export | false          |\n| --tls-no-verify      | OTEL_CLI_TLS_NO_VERIFY                | tls_no_verify    | false                  |\n| --tls-ca-cert        | OTEL_EXPORTER_OTLP_CERTIFICATE        | tls_ca_cert      | /ca/ca.pem             |\n| --tls-client-key     | OTEL_EXPORTER_OTLP_CLIENT_KEY         | tls_client_key   | /keys/client-key.pem   |\n| --tls-client-cert    | OTEL_EXPORTER_OTLP_CLIENT_CERTIFICATE | tls_client_cert  | /keys/client-cert.pem  |\n\n[Valid timeout units](https://pkg.go.dev/time#ParseDuration) are \"ns\", \"us\"/\"µs\", \"ms\", \"s\", \"m\", \"h\".\n\n### Endpoint URIs\n\notel-cli deviates from the OTel specification for endpoint URIs. Mainly, otel-cli supports\nbare host:port for grpc endpoints and continues to default to gRPC. The optional http/json\nis not supported by opentelemetry-go so otel-cli does not support it. To use gRPC with an\nhttp endpoint, set the protocol with --protocol or the envvar.\n\n   * bare `host:port` endpoints are assumed to be gRPC and are not supported for HTTP\n   * `http://` and `https://` are assumed to be HTTP unless --protocol is set to `grpc`.\n   * loopback addresses without an https:// prefix are assumed to be unencrypted\n\n### Header and Attribute formatting\n\nHeaders and attributes allow for `key=value,k=v` style formatting. Internally both\notel-cli and pflag use Go's `encoding/csv` to parse these values. Therefore, if you want\nto pass commas in a value, follow CSV quoting rules and quote the whole k=v pair.\nDouble quotes need to be escaped so the shell doesn't interpolate them. Once that's done,\nembedding commas will work fine.\n\n```shell\notel-cli span --attrs item1=value1,\\\"item2=value2,value3\\\",item3=value4\notel-cli span --attrs 'item1=value1,\"item2=value2,value3\",item3=value4'\n```\n\n### Docker TLS Certificates\n\nAs of release 0.4.2, otel-cli containers are built off the latest Alpine base\nimage which contains the base CA certificate bundles. In order to override\nthese for e.g. a self-signed certificate, the best bet is to volume mount your\nown /etc/ssl into the container, and it should get picked up by otel-cli and Go's\nTLS libraries.\n\n```shell\ndocker run -v /etc/ssl:/etc/ssl ghcr.io/equinix-labs/otel-cli:latest status\n```\n\n## Easy local dev\n\nWe want working on otel-cli to be easy, so we've provided a few different ways to get\nstarted. In general, there are three things you need:\n\n- A working Go environment\n- A built (or installed) copy of otel-cli itself\n- A system to receive/inspect the traces you generate\n\n### 1. A working Go environment\n\nProviding instructions on getting Go up and running on your machine is out of scope for this\nREADME. However, the good news is that it's fairly easy to do! You can follow the normal\n[Installation instructions](https://golang.org/doc/install) from the Go project itself.\n\n### 2. A built (or installed) copy of otel-cli itself\n\nIf you're planning on making changes to otel-cli, we recommend building the project locally: `go build`\n\nBut, if you just want to quickly try out otel-cli, you can also just install it directly: `go get github.com/equinix-labs/otel-cli`. This will place the command in your `GOPATH`. If your `GOPATH` is in your `PATH` you should be all set.\n\n### 3. A system to receive/inspect the traces you generate\n\notel-cli can run as a server and accept OTLP connections. It has two modes, one prints to your console\nwhile the other writes to JSON files.\n\n```shell\notel-cli server tui\notel-cli server json --dir $dir --timeout 60 --max-spans 5\n```\n\nMany SaaS vendors accept OTLP these days so one option is to send directly to those. This is not\nrecommended for production since it will slow your code down on the roundtrips. It is recommended\nto use an opentelemetry-collector locally.\n\nAnother option is to use [`otel-desktop-viewer`](https://github.com/CtrlSpice/otel-desktop-viewer). \nThis will bring up a server that can accept OTLP connections.\n\nIf you're not sure what to choose, try `otel-cli server tui` or `otel-desktop-viewer`.\n\n### `otel-desktop-viewer` setup\n\n```shell\n# install the CLI tool\ngo install github.com/CtrlSpice/otel-desktop-viewer@latest\n\n# run it!\n$(go env GOPATH)/bin/otel-desktop-viewer\n\n# if you have $GOPATH/bin added to your $PATH you can call it directly!\notel-desktop-viewer\n\n# if not you can add it to your $PATH by running this or adding it to\n# your startup script (usually ~/.bashrc or ~/.zshrc)\nexport PATH=\"$(go env GOPATH)/bin:$PATH\"\n```\n\nThe OpenTelemetry collector is listening on `localhost:4318`, and the UI will be running on\n`localhost:8000`.\n\n```shell\n# start the desktop viewer (best to do this in a separate terminal)\notel-desktop-viewer\n\n# configure otel-cli to send to our desktop viewer endpoint\nexport OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4318\n\n# use otel-cli to generate spans!\notel-cli exec --service my-service --name \"curl google\" curl https://google.com\n```\n\nThis trace will be available at `localhost:8000`.\n\n### SaaS tracing vendor\n\nWe've provided Honeycomb, LightStep, and Elastic configurations that you could also use,\nif you're using one of those vendors today. It's still pretty easy to get started:\n\n```shell\n# optional: to send data to an an OTLP-enabled tracing vendor, pass in your\n# API auth token over an environment variable and modify\n# `local/otel-vendor-config.yaml` according to the comments inside\nexport LIGHTSTEP_TOKEN= # Lightstep API key (otlp/1 in the yaml)\nexport HONEYCOMB_TEAM=  # Honeycomb API key (otlp/2 in the yaml)\nexport ELASTIC_TOKEN= # Elastic token for the APM server.\n\ndocker run \\\n   --env LIGHTSTEP_TOKEN \\\n   --env HONEYCOMB_TEAM \\\n   --env ELASTIC_TOKEN \\\n   --name otel-collector \\\n   --net host \\\n   --volume $(pwd)/configs/otel-vendor-config.yaml:/local.yaml \\\n   otel/opentelemetry-collector-contrib:0.101.0 \\\n      --config /local.yaml\n```\n\nThen it should just work to run otel-cli:\n\n```shell\n./otel-cli span -n \"testing\" -s \"my first test span\"\n# or for quick iterations:\ngo run . span -n \"testing\" -s \"my first test span\"\n```\n\n## Contributing\n\nPlease file issues and PRs on the GitHub project at https://github.com/equinix-labs/otel-cli\n\n## Releases\n\nReleases are managed by goreleaser. Currently this is limited to @tobert due to rules in\nthe equinix-labs organization. For now releases are not automated, but will be by the time\na v1.0 rolls out and the test suite is robust enough that we feel confident.\n\nTesting the release: `goreleaser release --snapshot --rm-dist`\n\nTo release, a GitHub personal access token is required. The release also needs to be tagged\nin git.\n\n```shell\ndocker login ghcr.io # log into GitHub Docker repo\ngh repo list         # make sure GitHub PAT is working\ngit checkout main    # release tags must be off the main branch\ngit pull --rebase    # get the latest HEAD\ngit tag v0.1.1       # tag HEAD with the next version\ngit push --tags      # push new tag up to GitHub\ngoreleaser release --rm-dist\n```\n\n## License\n\nApache 2.0, see LICENSE\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fequinix-labs%2Fotel-cli","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fequinix-labs%2Fotel-cli","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fequinix-labs%2Fotel-cli/lists"}