A GitHub Copilot plugin: one TOML file runs shell commands on Copilot lifecycle events and exports the output to an OpenTelemetry (OTLP/HTTP) endpoint.
- One config file, structured OTLP export, optional per-session traces.
- Zero dependencies (Python 3.11+ stdlib), fail-open, cross-platform.
copilot plugin install BenDutton/copilot-custom-loggingRestart Copilot CLI after installing — hooks load at startup.
Copy config.example.toml to
~/.copilot/copilot-otel-logging.toml, point endpoint at your collector, and
add a hook or two:
[otel]
endpoint = "https://collector.example.com:4318" # POSTs to {endpoint}/v1/logs
service_name = "github-copilot-logger"
[otel.headers] # Remove if your endpoint doesn't need auth
Authorization = "Bearer ${OTEL_TOKEN}" # ${ENV} expanded at runtime
[[hooks.UserPromptSubmit]] # Triggers on every prompt submission
name = "prompt" #
run = "printf '%s' \"$COPILOT_HOOK_PROMPT\"" # Log the prompt text
[[hooks.UserPromptSubmit]] # Triggers on every prompt submission
name = "github-user" #
run = "gh api user -q .login" # Log the GitHub username (requires `gh` CLI)Restart Copilot and submit a prompt — a log record lands at your endpoint.
Need a collector to test against locally? metafab/otel-gui is a simple OTLP collector with a built-in viewer, handy for local development.
See docs/example-hooks.md for more ready-to-use hooks (GitHub username, prompt, model, AIU usage, repo, branch, host).
The plugin registers a hook on six Copilot events and routes them all through
one dispatcher (otel_dispatch.py):
| Event | Fires when | Frequency |
|---|---|---|
SessionStart |
a new or resumed session begins | once at start |
SessionEnd |
the session terminates | once at end |
UserPromptSubmit |
you submit a prompt | every prompt |
PreToolUse |
before each tool executes | every tool call |
PostToolUse |
after each tool completes successfully | every tool call |
Stop |
the agent finishes a turn | every prompt |
For each event, the dispatcher reads the payload, loads your TOML config, runs
the commands you configured for that event (exposing payload fields as
COPILOT_HOOK_* environment variables), and POSTs their stdout as a single OTLP
log record to {endpoint}/v1/logs. An event with no configured commands does
nothing.
Note
Fail-open by design. The dispatcher always exits 0. A telemetry failure
(unreachable endpoint, bad config, failing command) is logged to stderr with
an [otel-logging] prefix but never blocks your session or your tools.
- GitHub Copilot CLI with plugin/hook support.
- Python 3.11+ on
PATH(python3, orpythonon Windows). Python 3.10 and earlier work only if thetomlipackage is installed. - An OTLP/HTTP receiver — an OpenTelemetry Collector with an
otlpreceiver, or any vendor endpoint that accepts OTLP/HTTP JSON.
- Configuration — config file locations, the
[otel]section, defining hooks, theCOPILOT_HOOK_*variables, output routing, and Windows support. - OTLP output — log record structure and session traces.
- Example hooks — copy-paste TOML for common signals.
- Enterprise deployment — managing the TOML at scale with Intune/MDM and enterprise-managed plugin standards.
- Development — tests, architecture, and regenerating
hooks.json.
Distribute copilot-otel-logging.toml at scale with Microsoft Intune or
another MDM, and govern rollout with GitHub's
enterprise plugin standards.
See docs/enterprise.md.
copilot plugin uninstall copilot-custom-logging