autotel
Version:
Write Once, Observe Anywhere
147 lines • 5.2 kB
text/typescript
import { ReadableSpan } from "@opentelemetry/sdk-trace-base";
import { Context } from "@opentelemetry/api";
import { LogRecordProcessor, SdkLogRecord } from "@opentelemetry/sdk-logs";
//#region src/policy.d.ts
/** A path into an attribute. `"ccn"` and `["ccn"]` are equivalent. */
type AttributePath = string | string[];
/**
* A single ANDed matcher. Exactly one field selector and exactly one match
* operator must be set. Regexes are RE2 in the spec but JS `RegExp` here —
* see {@link MAX_MATCH_LENGTH}.
*/
interface PolicyMatcher {
log_field?: string;
trace_field?: string;
span_attribute?: AttributePath;
log_attribute?: AttributePath;
resource_attribute?: AttributePath;
scope_attribute?: AttributePath;
span_kind?: string;
span_status?: string;
exact?: string;
regex?: string;
exists?: boolean;
starts_with?: string;
ends_with?: string;
contains?: string;
negate?: boolean;
case_insensitive?: boolean;
}
/** A field targeted by a transform operation. */
interface PolicyField {
log_field?: string;
log_attribute?: AttributePath;
resource_attribute?: AttributePath;
scope_attribute?: AttributePath;
}
interface PolicyLogTransform {
remove?: PolicyField[];
redact?: Array<PolicyField & {
replacement?: string;
}>;
rename?: Array<PolicyField & {
to: string;
upsert?: boolean;
}>;
add?: Array<PolicyField & {
value: string;
upsert?: boolean;
}>;
}
interface PolicyLogTarget {
match: PolicyMatcher[];
/** `"all"` (default), `"none"`, or a percentage (`"5.0"` or `5`). */
keep?: string | number;
transform?: PolicyLogTransform;
}
interface PolicyTraceTarget {
match: PolicyMatcher[];
keep?: {
/** 0-100. Omitted means keep all matching spans. */
percentage?: number;
mode?: string;
sampling_precision?: number;
hash_seed?: number;
fail_closed?: boolean;
};
}
/** A telemetry policy. Exactly one target must be set. */
interface Policy {
id: string;
name?: string;
description?: string;
enabled?: boolean;
labels?: Record<string, string>;
trace?: PolicyTraceTarget;
log?: PolicyLogTarget;
/** Recognised so it can be reported unsupported rather than silently ignored. */
metric?: unknown;
}
/**
* Values longer than this are not regex-matched (the matcher yields no match).
*
* The spec mandates RE2 for cross-implementation consistency; Node's `RegExp`
* backtracks, so an untrusted log body plus a pathological pattern is a DoS.
* Capping input bounds the damage without pulling in an RE2 binding.
*
* ponytail: length cap instead of a real RE2 engine — swap in a linear-time
* matcher if policies ever run against fully untrusted patterns.
*/
declare const MAX_MATCH_LENGTH = 4096;
/**
* Returns a reason string if the policy cannot be applied, or undefined if it can.
*
* Per spec an implementation MAY support a subset of stages but MUST skip the
* policy — never the telemetry — when it meets one it does not understand.
*/
declare function unsupportedReason(policy: Policy): string | undefined;
/**
* Replace the active policy set.
*
* Disabled policies are dropped (spec: they MUST be treated as if they do not
* exist) and unsupported ones are skipped with a warning.
*/
declare function setPolicies(policies: Policy[]): void;
/** The currently active (validated, enabled) policies. */
declare function getPolicies(): readonly Policy[];
declare function clearPolicies(): void;
/**
* A `SpanFilterPredicate` backed by the active policies. Returns true to keep.
*
* Fail-open: any error keeps the span.
*/
declare function policySpanFilter(span: ReadableSpan): boolean;
/**
* Applies `log` policies — keep first, then transform (spec stage order).
*
* Fail-open: any error emits the record unmodified.
*/
declare class PolicyLogRecordProcessor implements LogRecordProcessor {
private readonly wrapped;
constructor(wrapped: LogRecordProcessor);
onEmit(logRecord: SdkLogRecord, context?: Context): void;
shutdown(): Promise<void>;
forceFlush(): Promise<void>;
}
/** True when any active policy targets logs — used to skip wrapping otherwise. */
declare function hasLogPolicies(): boolean;
/**
* Load every policy from a `.json` file, or from every `.json` file in a
* directory.
*
* Fail-open: an unreadable or malformed file yields no policies from that file
* and warns; it never throws.
*/
declare function loadPolicies(target: string): Policy[];
/**
* The file policy provider: load `target` now and reload on change.
*
* Policies are expected to change outside the lifecycle of the process, so the
* watcher is what makes them dynamic. The watcher is unref'd — it never holds
* the process open.
*
* @returns a function that stops watching
*/
declare function watchPolicyFile(target: string): () => void;
//#endregion
export { watchPolicyFile as _, PolicyLogRecordProcessor as a, PolicyMatcher as c, getPolicies as d, hasLogPolicies as f, unsupportedReason as g, setPolicies as h, PolicyField as i, PolicyTraceTarget as l, policySpanFilter as m, MAX_MATCH_LENGTH as n, PolicyLogTarget as o, loadPolicies as p, Policy as r, PolicyLogTransform as s, AttributePath as t, clearPolicies as u };