autotel
Version:
Write Once, Observe Anywhere
591 lines (585 loc) • 26 kB
JavaScript
import { l as asString } from "./values-xBtdXtjA.js";
import { REDACTOR_PATTERNS } from "./attribute-redacting-processor.js";
import { C as URLAttributes, S as ThreadAttributes, _ as RPCAttributes, a as DeviceAttributes, b as SessionAttributes, c as FaaSAttributes, d as HTTPAttributes, f as K8sAttributes, g as ProcessAttributes, h as OTelAttributes, i as DBAttributes, l as FeatureFlagAttributes, m as NetworkAttributes, n as CodeAttributes, o as ErrorAttributes, p as MessagingAttributes, r as ContainerAttributes, s as ExceptionAttributes, t as CloudAttributes, u as GraphQLAttributes, v as ServerAddressAttributes, w as UserAttributes, x as TLSAttributes, y as ServiceAttributes } from "./registry-Cy4JjIB-.js";
import { resourceFromAttributes } from "@opentelemetry/resources";
//#region src/attributes/builders.ts
/**
* Attribute builders for constructing OpenTelemetry attributes
* Provides both key builders (Pattern A) and object builders (Pattern B)
*
* @example Pattern A: Key builders
* ```typescript
* attrs.user.id('123') // { 'user.id': '123' }
* attrs.user.email('user@example.com') // { 'user.email': 'user@example.com' }
* attrs.http.request.method('GET') // { 'http.request.method': 'GET' }
* attrs.http.response.statusCode(200) // { 'http.response.status_code': 200 }
* ```
*
* @example Pattern B: Object builders
* ```typescript
* attrs.user({ id: '123', email: 'user@example.com' })
* attrs.http.server({ method: 'GET', route: '/users/:id', statusCode: 200 })
* attrs.db.client({ system: 'postgresql', operation: 'SELECT', collectionName: 'users' })
* ```
*/
const attrs = {
user: {
id: (value) => ({ [UserAttributes.id]: value }),
email: (value) => ({ [UserAttributes.email]: value }),
name: (value) => ({ [UserAttributes.name]: value }),
fullName: (value) => ({ [UserAttributes.fullName]: value }),
hash: (value) => ({ [UserAttributes.hash]: value }),
roles: (value) => ({ [UserAttributes.roles]: value }),
data: (data) => {
const result = {};
if (data.id !== void 0) result[UserAttributes.id] = data.id;
if (data.email !== void 0) result[UserAttributes.email] = data.email;
if (data.name !== void 0) result[UserAttributes.name] = data.name;
if (data.fullName !== void 0) result[UserAttributes.fullName] = data.fullName;
if (data.hash !== void 0) result[UserAttributes.hash] = data.hash;
if (data.roles !== void 0) result[UserAttributes.roles] = data.roles;
return result;
}
},
session: {
id: (value) => ({ [SessionAttributes.id]: value }),
previousId: (value) => ({ [SessionAttributes.previousId]: value }),
data: (data) => {
const result = {};
if (data.id !== void 0) result[SessionAttributes.id] = data.id;
if (data.previousId !== void 0) result[SessionAttributes.previousId] = data.previousId;
return result;
}
},
device: {
id: (value) => ({ [DeviceAttributes.id]: value }),
manufacturer: (value) => ({ [DeviceAttributes.manufacturer]: value }),
modelIdentifier: (value) => ({ [DeviceAttributes.modelIdentifier]: value }),
modelName: (value) => ({ [DeviceAttributes.modelName]: value }),
data: (data) => {
const result = {};
if (data.id !== void 0) result[DeviceAttributes.id] = data.id;
if (data.manufacturer !== void 0) result[DeviceAttributes.manufacturer] = data.manufacturer;
if (data.modelIdentifier !== void 0) result[DeviceAttributes.modelIdentifier] = data.modelIdentifier;
if (data.modelName !== void 0) result[DeviceAttributes.modelName] = data.modelName;
return result;
}
},
http: {
request: {
method: (value) => ({ [HTTPAttributes.requestMethod]: value }),
methodOriginal: (value) => ({ [HTTPAttributes.requestMethodOriginal]: value }),
resendCount: (value) => ({ [HTTPAttributes.requestResendCount]: value }),
size: (value) => ({ [HTTPAttributes.requestSize]: value }),
bodySize: (value) => ({ [HTTPAttributes.requestBodySize]: value })
},
response: {
statusCode: (value) => ({ [HTTPAttributes.responseStatusCode]: value }),
size: (value) => ({ [HTTPAttributes.responseSize]: value }),
bodySize: (value) => ({ [HTTPAttributes.responseBodySize]: value })
},
route: (value) => ({ [HTTPAttributes.route]: value }),
connectionState: (value) => ({ [HTTPAttributes.connectionState]: value }),
server: (data) => {
const result = {};
if (data.method !== void 0) result[HTTPAttributes.requestMethod] = data.method;
if (data.route !== void 0) result[HTTPAttributes.route] = data.route;
if (data.statusCode !== void 0) result[HTTPAttributes.responseStatusCode] = data.statusCode;
if (data.bodySize !== void 0) result[HTTPAttributes.requestBodySize] = data.bodySize;
if (data.requestSize !== void 0) result[HTTPAttributes.requestSize] = data.requestSize;
if (data.responseSize !== void 0) result[HTTPAttributes.responseSize] = data.responseSize;
if (data.resendCount !== void 0) result[HTTPAttributes.requestResendCount] = data.resendCount;
return result;
},
client: (data) => {
const result = {};
if (data.method !== void 0) result[HTTPAttributes.requestMethod] = data.method;
if (data.url !== void 0) result[HTTPAttributes.route] = data.url;
if (data.statusCode !== void 0) result[HTTPAttributes.responseStatusCode] = data.statusCode;
return result;
}
},
db: { client: {
system: (value) => ({ [DBAttributes.systemName]: value }),
operation: (value) => ({ [DBAttributes.operationName]: value }),
collectionName: (value) => ({ [DBAttributes.collectionName]: value }),
namespace: (value) => ({ [DBAttributes.namespace]: value }),
statement: (value) => ({ [DBAttributes.statement]: value }),
querySummary: (value) => ({ [DBAttributes.querySummary]: value }),
queryText: (value) => ({ [DBAttributes.queryText]: value }),
responseStatus: (value) => ({ [DBAttributes.responseStatusCode]: value }),
rowsReturned: (value) => ({ [DBAttributes.responseReturnedRows]: value }),
data: (data) => {
const result = {};
if (data.system !== void 0) result[DBAttributes.systemName] = data.system;
if (data.operation !== void 0) result[DBAttributes.operationName] = data.operation;
if (data.collectionName !== void 0) result[DBAttributes.collectionName] = data.collectionName;
if (data.name !== void 0) result[DBAttributes.namespace] = data.name;
if (data.namespace !== void 0) result[DBAttributes.namespace] = data.namespace;
if (data.statement !== void 0) result[DBAttributes.statement] = data.statement;
if (data.querySummary !== void 0) result[DBAttributes.querySummary] = data.querySummary;
if (data.queryText !== void 0) result[DBAttributes.queryText] = data.queryText;
if (data.responseStatus !== void 0) result[DBAttributes.responseStatusCode] = data.responseStatus;
if (data.rowsReturned !== void 0) result[DBAttributes.responseReturnedRows] = data.rowsReturned;
return result;
}
} },
service: {
name: (value) => ({ [ServiceAttributes.name]: value }),
instance: (value) => ({ [ServiceAttributes.instance]: value }),
version: (value) => ({ [ServiceAttributes.version]: value }),
data: (data) => {
const result = {};
if (data.name !== void 0) result[ServiceAttributes.name] = data.name;
if (data.instance !== void 0) result[ServiceAttributes.instance] = data.instance;
if (data.version !== void 0) result[ServiceAttributes.version] = data.version;
return result;
}
},
network: {
peerAddress: (value) => ({ [NetworkAttributes.peerAddress]: value }),
peerPort: (value) => ({ [NetworkAttributes.peerPort]: value }),
transport: (value) => ({ [NetworkAttributes.transport]: value }),
protocolName: (value) => ({ [NetworkAttributes.protocolName]: value }),
protocolVersion: (value) => ({ [NetworkAttributes.protocolVersion]: value }),
data: (data) => {
const result = {};
if (data.peerAddress !== void 0) result[NetworkAttributes.peerAddress] = data.peerAddress;
if (data.peerPort !== void 0) result[NetworkAttributes.peerPort] = data.peerPort;
if (data.transport !== void 0) result[NetworkAttributes.transport] = data.transport;
if (data.protocolName !== void 0) result[NetworkAttributes.protocolName] = data.protocolName;
if (data.protocolVersion !== void 0) result[NetworkAttributes.protocolVersion] = data.protocolVersion;
return result;
}
},
server: {
address: (value) => ({ [ServerAddressAttributes.address]: value }),
port: (value) => ({ [ServerAddressAttributes.port]: value }),
socketAddress: (value) => ({ [ServerAddressAttributes.socketAddress]: value }),
data: (data) => {
const result = {};
if (data.address !== void 0) result[ServerAddressAttributes.address] = data.address;
if (data.port !== void 0) result[ServerAddressAttributes.port] = data.port;
if (data.socketAddress !== void 0) result[ServerAddressAttributes.socketAddress] = data.socketAddress;
return result;
}
},
url: {
scheme: (value) => ({ [URLAttributes.scheme]: value }),
full: (value) => ({ [URLAttributes.full]: value }),
path: (value) => ({ [URLAttributes.path]: value }),
query: (value) => ({ [URLAttributes.query]: value }),
fragment: (value) => ({ [URLAttributes.fragment]: value }),
data: (data) => {
const result = {};
if (data.scheme !== void 0) result[URLAttributes.scheme] = data.scheme;
if (data.full !== void 0) result[URLAttributes.full] = data.full;
if (data.path !== void 0) result[URLAttributes.path] = data.path;
if (data.query !== void 0) result[URLAttributes.query] = data.query;
if (data.fragment !== void 0) result[URLAttributes.fragment] = data.fragment;
return result;
}
},
error: {
type: (value) => ({ [ErrorAttributes.type]: value }),
message: (value) => ({ [ErrorAttributes.message]: value }),
stackTrace: (value) => ({ [ErrorAttributes.stackTrace]: value }),
code: (value) => ({ [ErrorAttributes.code]: value }),
data: (data) => {
const result = {};
if (data.type !== void 0) result[ErrorAttributes.type] = data.type;
if (data.message !== void 0) result[ErrorAttributes.message] = data.message;
if (data.stackTrace !== void 0) result[ErrorAttributes.stackTrace] = data.stackTrace;
if (data.code !== void 0) result[ErrorAttributes.code] = data.code;
return result;
}
},
exception: {
escaped: (value) => ({ [ExceptionAttributes.escaped]: value }),
message: (value) => ({ [ExceptionAttributes.message]: value }),
stackTrace: (value) => ({ [ExceptionAttributes.stackTrace]: value }),
type: (value) => ({ [ExceptionAttributes.type]: value }),
moduleName: (value) => ({ [ExceptionAttributes.moduleName]: value }),
data: (data) => {
const result = {};
if (data.escaped !== void 0) result[ExceptionAttributes.escaped] = data.escaped;
if (data.message !== void 0) result[ExceptionAttributes.message] = data.message;
if (data.stackTrace !== void 0) result[ExceptionAttributes.stackTrace] = data.stackTrace;
if (data.type !== void 0) result[ExceptionAttributes.type] = data.type;
if (data.moduleName !== void 0) result[ExceptionAttributes.moduleName] = data.moduleName;
return result;
}
},
process: {
pid: (value) => ({ [ProcessAttributes.pid]: value }),
executablePath: (value) => ({ [ProcessAttributes.executablePath]: value }),
command: (value) => ({ [ProcessAttributes.command]: value }),
owner: (value) => ({ [ProcessAttributes.owner]: value }),
data: (data) => {
const result = {};
if (data.pid !== void 0) result[ProcessAttributes.pid] = data.pid;
if (data.executablePath !== void 0) result[ProcessAttributes.executablePath] = data.executablePath;
if (data.command !== void 0) result[ProcessAttributes.command] = data.command;
if (data.owner !== void 0) result[ProcessAttributes.owner] = data.owner;
return result;
}
},
thread: {
id: (value) => ({ [ThreadAttributes.id]: value }),
name: (value) => ({ [ThreadAttributes.name]: value })
},
container: {
id: (value) => ({ [ContainerAttributes.id]: value }),
name: (value) => ({ [ContainerAttributes.name]: value }),
image: (value) => ({ [ContainerAttributes.image]: value }),
tag: (value) => ({ [ContainerAttributes.tag]: value }),
data: (data) => {
const result = {};
if (data.id !== void 0) result[ContainerAttributes.id] = data.id;
if (data.name !== void 0) result[ContainerAttributes.name] = data.name;
if (data.image !== void 0) result[ContainerAttributes.image] = data.image;
if (data.tag !== void 0) result[ContainerAttributes.tag] = data.tag;
return result;
}
},
k8s: {
podName: (value) => ({ [K8sAttributes.podName]: value }),
namespaceName: (value) => ({ [K8sAttributes.namespaceName]: value }),
deploymentName: (value) => ({ [K8sAttributes.deploymentName]: value }),
state: (value) => ({ [K8sAttributes.state]: value })
},
cloud: {
provider: (value) => ({ [CloudAttributes.provider]: value }),
accountId: (value) => ({ [CloudAttributes.accountId]: value }),
region: (value) => ({ [CloudAttributes.region]: value }),
availabilityZone: (value) => ({ [CloudAttributes.availabilityZone]: value }),
platform: (value) => ({ [CloudAttributes.platform]: value }),
data: (data) => {
const result = {};
if (data.provider !== void 0) result[CloudAttributes.provider] = data.provider;
if (data.accountId !== void 0) result[CloudAttributes.accountId] = data.accountId;
if (data.region !== void 0) result[CloudAttributes.region] = data.region;
if (data.availabilityZone !== void 0) result[CloudAttributes.availabilityZone] = data.availabilityZone;
if (data.platform !== void 0) result[CloudAttributes.platform] = data.platform;
return result;
}
},
faas: {
name: (value) => ({ [FaaSAttributes.name]: value }),
version: (value) => ({ [FaaSAttributes.version]: value }),
instance: (value) => ({ [FaaSAttributes.instance]: value }),
execution: (value) => ({ [FaaSAttributes.execution]: value }),
coldstart: (value) => ({ [FaaSAttributes.coldstart]: value })
},
featureFlag: {
key: (value) => ({ [FeatureFlagAttributes.key]: value }),
provider: (value) => ({ [FeatureFlagAttributes.provider]: value }),
variant: (value) => ({ [FeatureFlagAttributes.variant]: value })
},
messaging: {
system: (value) => ({ [MessagingAttributes.system]: value }),
destination: (value) => ({ [MessagingAttributes.destination]: value }),
operation: (value) => ({ [MessagingAttributes.operation]: value }),
messageId: (value) => ({ [MessagingAttributes.messageId]: value }),
conversationId: (value) => ({ [MessagingAttributes.conversationId]: value }),
data: (data) => {
const result = {};
if (data.system !== void 0) result[MessagingAttributes.system] = data.system;
if (data.destination !== void 0) result[MessagingAttributes.destination] = data.destination;
if (data.operation !== void 0) result[MessagingAttributes.operation] = data.operation;
if (data.messageId !== void 0) result[MessagingAttributes.messageId] = data.messageId;
if (data.conversationId !== void 0) result[MessagingAttributes.conversationId] = data.conversationId;
return result;
}
},
rpc: {
system: (value) => ({ [RPCAttributes.system]: value }),
service: (value) => ({ [RPCAttributes.service]: value }),
method: (value) => ({ [RPCAttributes.method]: value }),
grpcStatusCode: (value) => ({ [RPCAttributes.grpcStatusCode]: value })
},
graphql: {
document: (value) => ({ [GraphQLAttributes.document]: value }),
operationName: (value) => ({ [GraphQLAttributes.operationName]: value }),
operationType: (value) => ({ [GraphQLAttributes.operationType]: value })
},
otel: {
libraryName: (value) => ({ [OTelAttributes.libraryName]: value }),
libraryVersion: (value) => ({ [OTelAttributes.libraryVersion]: value }),
statusCode: (value) => ({ [OTelAttributes.statusCode]: value })
},
code: {
namespace: (value) => ({ [CodeAttributes.namespace]: value }),
filepath: (value) => ({ [CodeAttributes.filepath]: value }),
function: (value) => ({ [CodeAttributes.function]: value }),
class: (value) => ({ [CodeAttributes.class]: value }),
method: (value) => ({ [CodeAttributes.method]: value }),
column: (value) => ({ [CodeAttributes.column]: value }),
lineNumber: (value) => ({ [CodeAttributes.lineNumber]: value }),
repository: (value) => ({ [CodeAttributes.repository]: value }),
revision: (value) => ({ [CodeAttributes.revision]: value })
},
tls: {
protocolVersion: (value) => ({ [TLSAttributes.protocolVersion]: value }),
cipher: (value) => ({ [TLSAttributes.cipher]: value }),
curveName: (value) => ({ [TLSAttributes.curveName]: value }),
resumed: (value) => ({ [TLSAttributes.resumed]: value })
}
};
//#endregion
//#region src/attributes/validators.ts
/**
* Attributes OpenTelemetry has renamed, mapped to their replacement - or to
* `null` where the convention dropped them outright.
*/
const DEPRECATED_ATTRIBUTES = /* @__PURE__ */ new Map([
["enduser.id", "user.id"],
["enduser.role", "user.roles"],
["enduser.scope", null],
["http.method", "http.request.method"],
["http.host", "server.address"],
["http.status_code", "http.response.status_code"],
["http.target", "url.path"],
["http.url", "url.full"],
["http.user_agent", "user_agent.original"],
["http.flavor", "network.protocol.name"],
["http.scheme", "url.scheme"],
["http.server_name", "server.address"],
["db.name", "db.namespace"],
["db.operation", "db.operation.name"],
["db.statement", "db.query.text"],
["db.system", "db.system.name"],
["rpc.system", "rpc.system.name"],
["messaging.operation", "messaging.operation.type"],
["db.collection", "db.collection.name"],
["db.instance.id", null],
["db.jdbc.driver_classname", null],
["db.mssql.instance_name", "mssql.instance.name"],
["db.sql.table", "db.collection.name"],
["http.client_ip", "client.address"],
["user_agent.original", "user_agent.original"]
]);
const HTTP_METHODS = /* @__PURE__ */ new Set([
"GET",
"POST",
"PUT",
"DELETE",
"PATCH",
"HEAD",
"OPTIONS",
"TRACE",
"QUERY",
"_OTHER"
]);
function validateAttribute(key, value, policy = {}) {
const { guardrails = {} } = policy;
if (value === void 0 || value === null) return;
const stringValue = asString(value);
if (stringValue === void 0) return value;
if (guardrails.pii) {
const piiResult = applyPIIPolicy(key, stringValue, guardrails.pii);
if (piiResult !== stringValue) return piiResult;
}
if (guardrails.maxLength && stringValue.length > guardrails.maxLength) return truncateValue(key, stringValue, guardrails.maxLength);
if (guardrails.validateEnum && HTTP_METHODS.has(stringValue)) {
const normalizedMethod = normalizeHTTPMethod(stringValue);
if (normalizedMethod !== stringValue) return normalizedMethod;
}
return stringValue;
}
function applyPIIPolicy(key, value, pii) {
if (pii === "allow") return value;
if (pii === "redact") return redactIfPII(key, value);
if (pii === "hash") return hashIfPII(key, value);
if (pii === "block" && isPIIKey(key)) throw new Error(`PII attribute "${key}" is blocked by guardrails. Use pii: "allow" to enable it.`);
return value;
}
function isPIIKey(key) {
const piiKeyPatterns = [
"email",
"phone",
"ssn",
"credit_card",
"password",
"secret",
"token",
"api_key",
"authorization"
];
const lowerKey = key.toLowerCase();
return piiKeyPatterns.some((pattern) => lowerKey.includes(pattern));
}
function redactIfPII(key, value) {
if (isPIIKey(key)) {
for (const [, pattern] of Object.entries(REDACTOR_PATTERNS)) if (pattern instanceof RegExp && pattern.test(value)) return "[REDACTED]";
return "[REDACTED]";
}
return value;
}
function hashIfPII(key, value) {
if (!isPIIKey(key)) return value;
const FNV_PRIME = 16777619;
const FNV_OFFSET = 2166136261;
const hashes = [];
for (let round = 0; round < 4; round++) {
let hash = FNV_OFFSET;
for (let i = 0; i < value.length; i++) {
hash ^= (value.codePointAt(i) ?? 0) + round;
hash = Math.imul(hash, FNV_PRIME);
}
hashes.push(hash >>> 0);
}
return `hash_${hashes.map((h) => h.toString(16).padStart(8, "0")).join("")}`;
}
function truncateValue(key, value, maxLength) {
if (value.length <= maxLength) return value;
return value.slice(0, maxLength - 3) + "...";
}
function normalizeHTTPMethod(method) {
const upper = method.toUpperCase();
if (HTTP_METHODS.has(upper)) return upper;
return upper;
}
function checkDeprecatedAttribute(key, policy = {}) {
const { guardrails = {}, deprecatedWarnings = {} } = policy;
const { warnDeprecated = true } = guardrails;
if (!warnDeprecated) return null;
const replacement = DEPRECATED_ATTRIBUTES.get(key) ?? null;
if (DEPRECATED_ATTRIBUTES.has(key)) if (replacement === null) console.warn(`[autotel/attributes] Attribute "${key}" is deprecated and has no replacement. Remove or find a replacement in OpenTelemetry semantic conventions.`);
else console.warn(`[autotel/attributes] Attribute "${key}" is deprecated. Use "${replacement}" instead.`);
if (deprecatedWarnings[key]) console.warn(`[autotel/attributes] ${deprecatedWarnings[key]}`);
return replacement;
}
function autoRedactPII(attributes, policy = {}) {
const { guardrails = { pii: "redact" } } = policy;
const redacted = {};
for (const [key, value] of Object.entries(attributes)) redacted[key] = validateAttribute(key, value, { guardrails });
return redacted;
}
function defaultGuardrails() {
return {
pii: "redact",
maxLength: 255,
validateEnum: true,
warnDeprecated: true
};
}
//#endregion
//#region src/attributes/utils.ts
function mergeAttrs(...attrSets) {
const result = {};
for (const attrSet of attrSets) if (attrSet) Object.assign(result, attrSet);
return result;
}
function safeSetAttributes(span, attrs, policy) {
const mergedGuardrails = {
...defaultGuardrails(),
...policy?.guardrails
};
const effectivePolicy = {
...policy,
guardrails: mergedGuardrails
};
const validated = autoRedactPII(attrs, effectivePolicy);
const sanitizedAttrs = {};
for (const [key, value] of Object.entries(validated)) if (value !== void 0) {
checkDeprecatedAttribute(key, effectivePolicy);
const validatedValue = validateAttribute(key, value, effectivePolicy);
if (validatedValue !== void 0) sanitizedAttrs[key] = validatedValue;
}
span.setAttributes(sanitizedAttrs);
}
//#endregion
//#region src/attributes/attachers.ts
function setUser(spanOrContext, data, guardrails) {
safeSetAttributes(spanOrContext, attrs.user.data(data), guardrails);
}
function setSession(spanOrContext, data, guardrails) {
safeSetAttributes(spanOrContext, attrs.session.data(data), guardrails);
}
function setDevice(spanOrContext, data, guardrails) {
safeSetAttributes(spanOrContext, attrs.device.data(data), guardrails);
}
function httpServer(spanOrContext, data, guardrails) {
const attributes = attrs.http.server(data);
if ("updateName" in spanOrContext && data.method && data.route) spanOrContext.updateName(`HTTP ${data.method} ${data.route}`);
safeSetAttributes(spanOrContext, attributes, guardrails);
}
function httpClient(spanOrContext, data, guardrails) {
safeSetAttributes(spanOrContext, attrs.http.client(data), guardrails);
}
function dbClient(spanOrContext, data, guardrails) {
safeSetAttributes(spanOrContext, attrs.db.client.data(data), guardrails);
}
/**
* Merge service attributes into a Resource and return a new Resource.
*
* Resource.attributes is readonly, so this function returns a new merged
* Resource rather than mutating the input.
*
* @param resource - The existing resource to merge with
* @param data - Service attributes to add
* @returns A new Resource with the merged attributes
*
* @example
* ```typescript
* const baseResource = Resource.default();
* const enrichedResource = mergeServiceResource(baseResource, {
* name: 'my-service',
* version: '1.0.0',
* });
* ```
*/
function mergeServiceResource(resource, data) {
const attributes = attrs.service.data(data);
return resource.merge(resourceFromAttributes(attributes));
}
function identify(spanOrContext, data, guardrails) {
const allAttrs = [];
if (data.user) allAttrs.push(attrs.user.data(data.user));
if (data.session) allAttrs.push(attrs.session.data(data.session));
if (data.device) allAttrs.push(attrs.device.data(data.device));
const merged = {};
for (const attrSet of allAttrs) Object.assign(merged, attrSet);
safeSetAttributes(spanOrContext, merged, guardrails);
}
function request(spanOrContext, data, guardrails) {
const httpAttrs = attrs.http.server(data);
const networkAttrs = attrs.network.peerAddress(data.clientIp || "");
safeSetAttributes(spanOrContext, {
...httpAttrs,
...networkAttrs
}, guardrails);
}
function setError(spanOrContext, data, guardrails) {
safeSetAttributes(spanOrContext, attrs.error.data(data), guardrails);
}
function setException(spanOrContext, data, guardrails) {
safeSetAttributes(spanOrContext, attrs.exception.data(data), guardrails);
}
//#endregion
//#region src/attributes/domains.ts
/**
* Domain helpers for common attribute patterns
* These bundle multiple attribute groups into semantic helpers
*/
function transaction(spanOrContext, config, guardrails) {
const userAttrs = attrs.user.data(config.user || {});
const sessionAttrs = attrs.session.data(config.session || {});
const httpAttrs = attrs.http.server({
method: config.method,
route: config.route,
statusCode: config.statusCode
});
const networkAttrs = attrs.network.peerAddress(config.clientIp || "");
const merged = {
...userAttrs,
...sessionAttrs,
...httpAttrs,
...networkAttrs
};
if (config.method && config.route && "updateName" in spanOrContext) spanOrContext.updateName(`HTTP ${config.method} ${config.route}`);
safeSetAttributes(spanOrContext, merged, guardrails);
}
//#endregion
export { defaultGuardrails as _, identify as a, setDevice as c, setSession as d, setUser as f, checkDeprecatedAttribute as g, autoRedactPII as h, httpServer as i, setError as l, safeSetAttributes as m, dbClient as n, mergeServiceResource as o, mergeAttrs as p, httpClient as r, request as s, transaction as t, setException as u, validateAttribute as v, attrs as y };