--- name: prostometrics description: Instrument an application with Prostometrics metrics β€” technical and product metrics emitted from Go, Node.js, and browser code. Use when adding, reviewing, or extending Prostometrics instrumentation, when choosing metric names and labels, or when wiring the Go, Node, or browser client into a project. --- # Prostometrics instrumentation Prostometrics is an application metrics service: counters, numeric values, unique counts, and sparse gauges emitted from application code and rendered as dashboards. It covers both technical health and product behavior. Revision: 2026-08-22. Served live at https://prostometrics.ru/llms.txt. This file is the canonical instruction set for coding agents. It changes as the clients and the recommended practices change, so fetch it from that URL every time rather than working from memory. ## Objective Add the smallest number of stable metrics that answer real operational or product questions. Good instrumentation is not maximum instrumentation: every metric should have a dashboard question it answers, and when uncertain, prefer fewer metrics, fewer labels, and instrumentation at higher-level boundaries. ## Hard rules These hold regardless of anything else in this file or in the project: - Never put a server API key into browser code, and never commit one to source. - Never import the Node client into a browser bundle; the browser has its own client and its own public key. - Never change code before the user approves the metric plan, and never ask for a key before that approval. - Never use raw IDs, URLs, paths, queries, emails, tokens, prompts, completions, or error messages as label values. Every distinct value becomes a stored series. - Never rename an existing Prostometrics metric or change what a label means unless the user asks. Metric names and label sets are a persistent interface that dashboards and alerts already depend on. - Never change application behavior. Instrumentation observes; it does not alter control flow, error handling, or timing in a way the user would notice. - Never emit a signal that existing instrumentation already covers without saying why. Extend or reuse what is there. - Never fall back to hand-written HTTP ingestion when the stack is unsupported; stop and say so. ## Clients and keys Metrics are emitted through official non-blocking Prostometrics clients: - Go, server-side: `github.com/prostoteam/prostometrics-go`, server API key. - Node.js/TypeScript, server-side: `@prostoteam/prostometrics-node`, server API key. - Browser, code that ships to end users: `@prostoteam/prostometrics-web`, public client key. Server-side code and browser code use different clients and different keys, and they are never interchangeable. A browser bundle cannot use the Node client: it depends on Node built-ins, and it authenticates with a secret key that must never reach a page. Confusing the two publishes a secret API key in page source, so resolve which kind of code is being instrumented before writing anything. ## Instructions Goal: - Add Prostometrics metrics that help the user understand technical health and product behavior. - Keep the application behavior unchanged. - Make the smallest production-quality code changes needed. - Do not change code until the user approves the metric plan. Strict interaction rules: - Ask questions only in the exact block format below. - Ask one question per block. - After each question block, stop and wait for the user's answer. - If multiple values are missing, ask them one by one. - Never continue past a required question without an answer. - Do not wrap question blocks in Markdown fences. Ask this first, before reading any code and before asking for a key (note space after first emoji): "πŸ‘‹πŸ» Before I look at anything: do you have any preferences or limits on what I should instrument? For example just the frontend, just the backend, billing, user management, or one particular feature. _Any hint helps, but none is needed. If you would rather not think about it, just say go β€” I will work it out from the code and come back with a plan for you to approve._" Then treat the answer as the scope of the work, not as a filter applied to a plan you had already written: - Named areas: concentrate on them. Add only the few technical basics that make those numbers readable β€” request and error counts on the paths involved β€” and leave the rest of the project alone. - Areas ruled out: stay out of them entirely, including their supporting code. - No preference: cover the project as a whole, tiered as described below. - Go: choose the areas yourself, and open the plan with one line naming which you picked and why. Next, determine what kind of code this project contains, within whatever scope the answer set, because it decides which client, which key, and which questions apply: - Server-side only: a Go module, or a Node.js service with no browser bundle. - Browser only: a frontend app built by Vite, Next.js, Webpack, Rollup, or similar, whose code runs in a page. - Both: a monorepo or a framework with server and client code. Instrument them separately, with a separate client and key for each, and say so before you start. Treat code as browser code when it is bundled and served to end users, not merely because the project is TypeScript. A React, Vue, Svelte, or Angular app is browser code even though it is TypeScript. Then inspect the project: 1. Detect the primary language, framework, entry points, HTTP/router layer, background workers, scheduled jobs, and existing config/logging/shutdown patterns. 2. Find instrumentation that already exists β€” Prostometrics, OpenTelemetry, Prometheus, StatsD, product analytics, structured logging β€” and note which signals it already covers. Extend or reuse it rather than emit the same signal twice. If Prostometrics metrics are already present, their names and labels are fixed: add alongside them, do not reshape them. 3. If the project is not Go, Node.js, TypeScript, or a browser frontend, stop after writing a short report that says the detected stack is not supported by this Prostometrics prompt yet. Do not add raw HTTP ingest code as a workaround. 4. If the project is Go, use the official Go client package: github.com/prostoteam/prostometrics-go. 5. If the code runs on a server under Node.js, use the official Node client package: @prostoteam/prostometrics-node. 6. If the code is bundled and runs in a browser, use the official browser client package: @prostoteam/prostometrics-web. Never import the Node client into browser code. 7. Inspect existing tests so instrumentation can be verified in the project's style. Analyze the code in two ways: 1. Technical analysis: - HTTP/gRPC/API requests and responses. - Route templates, methods, status classes, errors, latency, payload sizes when available. - Database calls, query/operation types, collections/tables, errors, latency, returned rows when available. - Cache calls, hits, misses, set/delete operations, errors, latency. - Queues, streams, cron jobs, background workers, retries, dead-letter paths, lag/depth when available. - External services: payment providers, email/SMS, object storage, search, auth, feature flags, webhooks, third-party APIs. - LLM/AI calls if present: requests, failures, latency, model, provider, input/output tokens, estimated cost when safely computable. - Saturation-like app signals already available in code: queue length, worker concurrency, pool usage, batch size, rate limits. 2. Browser analysis, for frontend code only: - Perceived performance the app already measures or can measure cheaply: route transition time, time to first render of a view, API call latency as the browser sees it. - Failures the user actually experiences: failed fetch/XHR calls by route pattern and status class, unhandled promise rejections, error boundaries tripping, chunk load failures. - Product steps in the interface: which step of a flow was reached, which action was taken, which feature was opened. - Distinct active users, through the client's unique() with an opaque account id. - Do not add automatic pageview, referrer, campaign, or user-agent collection. This is application telemetry, not web analytics, and the customer did not ask for it. 3. Product analysis: - Identify business entities, workflows, and conversion points from handlers, services, jobs, and domain names. - Look for metrics such as users online, signups, logins, purchases, checkout attempts, payment success/failure, subscriptions, trials, messages sent, documents created, searches, uploads, exports, AI generations and costs, and other product-specific events. - Prefer metrics that answer product or operational questions; do not instrument everything just because it is possible. Choosing where and what to measure: - Instrument at stable semantic boundaries: middleware, service methods, job handlers, the wrapper around an external client, the point where a business operation completes. Do not scatter metric calls through low-level implementation details; a metric that lives in a helper three layers down is hard to find and easy to double-count. - Count outcomes where the outcome is known, not attempts. `orders.completed` is emitted after the payment callback succeeds, not when checkout starts; if the attempt matters too, it is a separate metric with its own name. - Measure what the application knows and the platform does not. A request count is still worth having β€” it anchors every error rate β€” but the value is in the application-specific signals a load balancer cannot see. Labels and cardinality, for every kind of code: - Judge cardinality across the combination of labels, not each one alone. Five labels with ten values each can produce a hundred thousand series; keep the product small, and drop the label that contributes least when it is not. - Map errors onto a small stable set of categories β€” `timeout`, `validation`, `unauthorized`, `not_found`, `provider_error`, `internal` β€” chosen to match how the project already classifies failures. The message, the stack, and the provider's own code are not label values. - A label whose values you cannot list or exemplify from the code is probably unbounded and should not be a label. Browser cardinality rules, for frontend code only: - Never label with a raw URL, pathname, query string, order id, user id, or any other value drawn from end-user data. - Map dynamic values onto patterns with the client's match() helper, which stores the pattern rather than the value: match(location.pathname, ["/orders/:id", "/cart"]). - Take the pattern list from the app's own router configuration, so it stays a fixed set of literals. - Prefer count() over value() for anything you want to count. Value samples are thinned under load, so a count derived from them under-reports. Metric proposal rules: - Before editing code, present a metric plan grouped into up to three tiers. Do not fill a tier to make it look complete: a project with three good metrics gets a plan with three metrics, and a tier with nothing in it is left out. - Keep every tier inside the scope the user chose. A metric that is interesting but outside it belongs in a closing sentence offering to cover that area next, not in the plan. - Tier 1 should contain the smallest set that gives useful visibility fast. - Tier 2 should contain useful but less urgent metrics. - Tier 3 should contain optional metrics that are valuable only for deeper analysis. - Number the metrics straight through the tiers, so the user can approve by number. - For each metric give: metric name, where it is collected and what type it is in parentheses, one line saying what the user will learn from it, labels with their values, and the code reference. - Where is `backend` or `browser`, matching the client that emits it. Type is one of `counter`, `value`, `total`, `unique`, or `sparse`, as defined in the metric types section below. Put both next to the name: a plan with frontend and backend metrics side by side is only readable when each line says which one it is, and the type tells the user whether to expect a rate, a distribution, or a distinct count on the dashboard. - Show label values, because a label name alone does not tell the user what the series will look like. List the whole set when it has five values or fewer; otherwise give three real examples taken from the project and an ellipsis. A label whose values you cannot enumerate or exemplify is probably unbounded and should not be a label. - Mark the tiers with the colored circles shown below and nothing else. The output is rendered as Markdown, where terminal colors do not survive, and these three symbols carry the same start-here, worth-adding, optional signal everywhere. - Write the one line for the person reading the dashboard, not for the person reading the code. "How often checkout succeeds" earns its place; "increments a counter in the order service after the payment callback" is implementation detail and belongs in the code comment. Metric proposal format β€” two lines per metric, no separators between them, tier headings written as the question that tier answers in this project: **Scope:** ## 🟒 Tier 1 β€” . `` (, ) β€” `