
Create Evlog Adapter
FreeEasily add new event log adapters for observability platforms.
Free · Opens the source repo
What Create Evlog Adapter does
The Create Evlog Adapter skill facilitates the integration of new drain adapters into the Evlog package, allowing developers to send wide events to external observability platforms such as Elasticsearch, Honeycomb, and SigNoz. This skill is particularly useful for those looking to extend the capabilities of Evlog by creating custom adapters that adhere to the established architecture and conventions of the Evlog toolkit.
When utilizing this skill, developers will follow a structured process to ensure that all necessary components of the adapter are created and configured correctly. The skill provides a checklist of touchpoints that must be addressed, including creating the adapter source, updating build configurations, modifying package exports, and ensuring comprehensive documentation and testing. By following these guidelines, users can maintain consistency and reliability across their adapters, making it easier to manage and integrate new functionalities.
This skill is designed for developers who are familiar with the Evlog package and are looking to enhance its observability features. It streamlines the process of creating new adapters, ensuring that all aspects, from source code to documentation, are covered. The skill emphasizes best practices in naming conventions, configuration resolution, and testing, which are crucial for maintaining high-quality code in collaborative environments.
In summary, the Create Evlog Adapter skill is an essential tool for developers aiming to expand the capabilities of the Evlog package. It provides a clear framework for creating robust and well-documented adapters that can seamlessly integrate with various observability platforms, enhancing the overall functionality of event logging systems.
When to use it
Use this skill when you need to create a new drain adapter for an observability platform within the Evlog framework.
When not to use it
This skill is not suitable for users unfamiliar with the Evlog package or those who do not require custom event log adapters.
What you can build with it
Integrating with Elasticsearch
Use this skill to create a custom adapter for sending events to Elasticsearch, enhancing your data observability.
Adding a Honeycomb Adapter
Leverage this skill to build a Honeycomb drain adapter, allowing for better event tracking and analysis.
Customizing Event Logging
Utilize this skill to create tailored adapters that meet specific logging requirements for your observability needs.
How to install Create Evlog Adapter
View source1. Install with the skills CLI
npx skills add hugorcd/evlog/create-adapter --agent claude-code2. Or install it manually
Download the skill folder and drop it into ~/.claude/skills/ for all projects, or .claude/skills/ to scope it to one repo. Restart Claude Code so it picks up the new skill.
Anthropic's agentic coding CLI, and the reference implementation of Agent Skills. Drop a skill folder into ~/.claude/skills and Claude Code loads it automatically whenever a task matches the skill's description. Claude Code docs
Inside SKILL.md
Written by hugorcdCreate evlog Adapter
Add a new built-in adapter to evlog. Every adapter follows the same architecture and is built on the public toolkit primitives in evlog/toolkit — so a community adapter has the same shape as a built-in one.
PR Title
feat({name}): add the {Name} drain adapter
Recent examples: feat(loki): add the Grafana Loki drain adapter, feat(clickhouse): add the ClickHouse drain adapter. Use the adapter name as the conventional-commit scope — and register that scope (see touchpoint 11).
Scope timing caveat: the semantic PR check reads its scope list from the base branch, so a brand-new scope can't validate the very PR that introduces it. Either register the scope in a small preceding PR (the Loki/ClickHouse pattern), or use an unscoped title (feat: add the {Name} drain adapter) on the introducing PR.
Touchpoints Checklist
| # | File | Action |
|---|---|---|
| 1 | packages/evlog/src/adapters/{name}.ts | Create adapter source (built on defineHttpDrain from ../shared/drain) |
| 2 | packages/evlog/tsdown.config.ts | Add build entry |
| 3 | packages/evlog/package.json | Add exports + typesVersions entries |
| 4 | packages/evlog/test/adapters/{name}.test.ts | Create unit tests (use test/helpers/fetch.ts) |
| 5 | packages/evlog/test/e2e/{name}.e2e.ts | Create e2e test gated on env vars; extend the docker sandbox if self-hostable |
| 6 | packages/evlog/test/toolkit/__snapshots__/api-surface.test.ts.snap | Regenerated by running the tests after a build (pnpm run build then pnpm test) |
| 7 | apps/docs/content/4.integrate/adapters/{category}/{NN}.{name}.md | Create adapter doc page in the right category |
| 8 | apps/docs/content/4.integrate/adapters/01.overview.md | Add adapter to overview (frontmatter link + card) |
| 9 | apps/docs/skills/review-logging-patterns/SKILL.md | Add adapter row in the Drain Adapters table + frontmatter description |
| 10 | .changeset/{name}-adapter.md | Create changeset (minor) describing the adapter |
| 11 | .github/workflows/semantic-pull-request.yml + .github/pull_request_template.md | Register {name} as a PR scope in both files |
Important: Do NOT consider the task complete until all 11 touchpoints have been addressed.
Naming Conventions
Use these placeholders consistently:
| Placeholder | Example (Loki) | Usage |
|---|---|---|
{name} | loki | File names, import paths, env var suffix, PR scope |
{Name} | Loki | PascalCase in function/interface names |
{NAME} | LOKI | SCREAMING_CASE in env var prefixes |
Standard option naming (use these exact names):
| Concept | Standard option name |
|---|---|
| Bearer-style API secret | apiKey |
| Base URL of the ingest API | endpoint |
| Service identifier | serviceName |
| Request timeout (ms) | timeout |
| Retry attempts on transient failures | retries |
If a service historically used a different name (token, sourceToken, …) keep it as a deprecated alias via applyDeprecatedAlias — see Axiom and Better Stack for the pattern.
Step 1: Adapter Source — built on defineHttpDrain
Create packages/evlog/src/adapters/{name}.ts. Read references/adapter-template.md for the full annotated template. loki.ts and clickhouse.ts are the most recent reference implementations.
The contract is defineHttpDrain<TConfig>({ name, label, resolve, encode }). You only ship two pieces of logic:
resolve()— produce a fully-resolved config ornullto skip. UseresolveAdapterConfigfor the standard precedence (overrides →runtimeConfig.evlog.{name}→runtimeConfig.{name}→ env vars). ListNUXT_{NAME}_*before{NAME}_*inConfigField.envfor silent Nuxt compat; show only{NAME}_*in user-facing messages viaformatPublicEnvKeys.encode(events, config)— a privateencode{Name}Request(events, config): HttpDrainRequestreturning{ url, headers, body }for a batch. HTTP transport, identity headers, retries, timeout, and error logging are handled bydefineHttpDrain(viahttpPost).
Key rules:
- Single factory. Export one
create{Name}Drain(overrides?: Partial<{Name}Config>). No dual-API factories: if a service has multiple ingest modes (logs vs events), expose them via amodeoption (see PostHog). - No HTTP code in the adapter. Never call
fetchdirectly. If the service truly needs custom transport (binary envelopes, non-HTTP), usedefineDrainfrom../shared/draininstead — seefs.tsandmemory.ts. - Encode parity. The standalone
sendTo{Name}/sendBatchTo{Name}helpers must reuse the same privateencode{Name}Request()and go throughsendEncodedDrainRequest(request, { label, source, timeout, retries })— never a separate fetch path.test/adapters/encode-parity.test.tspins this for a subset of adapters; add the new one to it (not every existing adapter is registered there yet — that's a gap, not a license to skip). - No bespoke config resolution. Always go through
resolveAdapterConfig. Deprecated aliases (token→apiKey) go throughapplyDeprecatedAlias. - Exported converters. If the service needs a specific event shape, export
to{Name}Event()/build{Name}Payload()helpers so they're testable independently. - Edge-safe. Adapters run on Cloudflare Workers: no
Buffer(useTextEncoder+btoa, seeloki.ts), no Node-only APIs.fs.tsshows theisEdgeRuntime()guard pattern when a runtime genuinely can't be supported.
Step 2: Build Config
Add a build entry in packages/evlog/tsdown.config.ts alongside the existing adapters:
'adapters/{name}': 'src/adapters/{name}.ts',
Follow the existing ordering in that file.
Step 3: Package Exports
In packages/evlog/package.json, add two entries (after the last adapter — check the current list rather than assuming):
In exports:
"./{name}": {
"types": "./dist/adapters/{name}.d.mts",
"import": "./dist/adapters/{name}.mjs"
}
In typesVersions["*"]:
"{name}": [
"./dist/adapters/{name}.d.mts"
]
Any export added to package.json without a matching tsdown.config.ts entry (and vice versa) fails test/toolkit/api-surface.test.ts — that's touchpoint 6.
Step 4: Unit Tests
Create packages/evlog/test/adapters/{name}.test.ts. Read references/test-template.md for the full annotated template, and packages/evlog/test/README.md for the repo-wide conventions.
Non-negotiables from the test README:
- Use
mockFetch()/getFetchCall/getFetchJson/getFetchHeadersfromtest/helpers/fetch.ts— never hand-rollvi.spyOn(globalThis, 'fetch')boilerplate. - Clean up any env vars the adapter reads in
afterEach. - Test the exported pure helpers (
to{Name}Event,build{Name}Payload, URL resolvers) directly, onedescribeper helper.
Required test categories:
- URL construction (default + custom endpoint, trailing-slash tolerance)
- Headers (auth, content-type, service-specific)
- Request body format (JSON structure matches service API)
- Skip behavior when
apiKey(or required field) is missing - Batch operations (multiple events in one request, empty batch skips fetch)
- Deprecated alias still works (when applicable)
- Add the adapter to
test/adapters/encode-parity.test.ts
Step 5: E2E Test + Sandbox
Create packages/evlog/test/e2e/{name}.e2e.ts, gated on the adapter's env vars (skipped when absent). Run with pnpm test:e2e.
If the service is self-hostable, extend the local sandbox so the adapter can be exercised without cloud credentials:
packages/evlog/test/e2e/docker-compose.yml— add the servicepackages/evlog/test/e2e/seed.mjs— fan the seeder out to the new backendpackages/evlog/test/e2e/README.md— document it- Root
package.jsonsandbox:e2escript — add the local env var if needed
See the Loki and ClickHouse setups as references.
Step 6: Adapter Documentation Page
Read apps/docs/AGENTS.md before touching anything under apps/docs/ (steps 6–8).
Adapter docs live in three categories under apps/docs/content/4.integrate/adapters/:
| Category | Directory | Examples |
|---|---|---|
| Cloud (SaaS only) | cloud/ | Axiom, PostHog, Sentry, Better Stack, Datadog |
| Cloud or Self-Hosted | hybrid/ | Loki, ClickHouse, OTLP, HyperDX |
| Self-Hosted (local only) | self-hosted/ | FS, NuxtHub, Memory |
Create {NN}.{name}.md in the right category with the next available number. Use the Loki page (hybrid/01.loki.md) as a reference for frontmatter, tone, and sections. Key sections: intro, quick setup, configuration (env vars table + priority), advanced usage, querying in the target service, troubleshooting, direct API usage, next steps.
Important: multi-framework examples. The Quick Start section must include a ::code-group with tabs for the supported frameworks (Nuxt/Nitro, Hono, Express, Fastify, Elysia, NestJS, Standalone). Do not only show Nitro examples.
Step 7: Update Adapters Overview Page
Edit apps/docs/content/4.integrate/adapters/01.overview.md in two places (follow the pattern of existing adapters):
- Frontmatter
linksarray — add a link entry with icon and/integrate/adapters/{category}/{name}path, in category order ::card-groupsection — add a card block in the matching position
Step 8: Update the Public Skill
In apps/docs/skills/review-logging-patterns/SKILL.md (published on evlog.dev via /.well-known/skills/):
- Add a row to the Drain Adapters table:
| {Name} | evlog/{name} | {NAME}_API_KEY, ... | - Add the adapter name to the
description:line in the YAML frontmatter
Step 9: Changeset
Create .changeset/{name}-adapter.md with a minor bump. Write it like a release note: what the adapter does, the deployment modes it covers, the key options, the env vars, and the direct-send helpers. See .changeset entries from the Loki/ClickHouse PRs for the expected depth.
Step 10: PR Scopes
Add {name} to the scopes list in .github/workflows/semantic-pull-request.yml and to the Scopes section of .github/pull_request_template.md, in alphabetical order. Remember the timing caveat from the PR Title section: this registration only takes effect for PRs whose base branch already contains it.
Verification
After a clean install, prepare generated workspace types from the repo root first, then run the package checks:
pnpm run dev:prepare
cd packages/evlog
pnpm run lint
pnpm run typecheck
pnpm run build # required before test — api-surface snapshot is gated on dist/
pnpm run test
Frequently asked questions about Create Evlog Adapter
Similar skills
WinMD API Search
Easily find and explore Windows desktop APIs.
WebMCPify
Transform any web app into an agent-ready platform.
Phoenix Tracing
Instrument LLM applications with OpenInference tracing.
Foundry Hosted Agent CopilotKit
Guidance for developing agentic web apps on Azure.
Power Automate Foundation
Connect AI agents to Power Automate seamlessly.
Power Automate Flow Builder
Efficiently build and deploy Power Automate flows programmatically.
