@smithers-orchestrator/observability 0.16.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/package.json +44 -0
- package/src/MetricName.ts +1 -0
- package/src/MetricsServiceLive.js +9 -0
- package/src/ResolvedSmithersObservabilityOptions.ts +10 -0
- package/src/SmithersEvent.ts +603 -0
- package/src/SmithersLogFormat.ts +1 -0
- package/src/SmithersMetricDefinition.ts +15 -0
- package/src/SmithersMetricType.ts +1 -0
- package/src/SmithersMetricUnit.ts +8 -0
- package/src/SmithersObservability.js +6 -0
- package/src/SmithersObservabilityOptions.ts +10 -0
- package/src/SmithersObservabilityService.ts +15 -0
- package/src/_coreCorrelation/CorrelationContext.ts +10 -0
- package/src/_coreCorrelation/CorrelationContextLive.js +11 -0
- package/src/_coreCorrelation/CorrelationContextService.js +6 -0
- package/src/_coreCorrelation/CorrelationContextServiceShape.ts +14 -0
- package/src/_coreCorrelation/CorrelationPatch.ts +3 -0
- package/src/_coreCorrelation/_correlationStorage.js +4 -0
- package/src/_coreCorrelation/correlationContextFiberRef.js +2 -0
- package/src/_coreCorrelation/correlationContextToLogAnnotations.js +28 -0
- package/src/_coreCorrelation/getCurrentCorrelationContext.js +9 -0
- package/src/_coreCorrelation/getCurrentCorrelationContextEffect.js +11 -0
- package/src/_coreCorrelation/index.js +14 -0
- package/src/_coreCorrelation/mergeCorrelationContext.js +61 -0
- package/src/_coreCorrelation/runWithCorrelationContext.js +14 -0
- package/src/_coreCorrelation/updateCurrentCorrelationContext.js +19 -0
- package/src/_coreCorrelation/withCorrelationContext.js +15 -0
- package/src/_coreCorrelation/withCurrentCorrelationContext.js +13 -0
- package/src/_coreMetrics.js +510 -0
- package/src/_coreMetricsShape.ts +55 -0
- package/src/_corePrometheus.js +93 -0
- package/src/_corePrometheusShape.ts +11 -0
- package/src/_coreTracing.js +142 -0
- package/src/_coreTracingShape.ts +17 -0
- package/src/_smithersSpanAttributeAliases.js +19 -0
- package/src/_smithersTraceSpanStorage.js +3 -0
- package/src/annotateSmithersTrace.js +11 -0
- package/src/correlation.js +20 -0
- package/src/createSmithersObservabilityLayer.js +49 -0
- package/src/createSmithersOtelLayer.js +21 -0
- package/src/createSmithersRuntimeLayer.js +2 -0
- package/src/getCurrentSmithersTraceAnnotations.js +14 -0
- package/src/getCurrentSmithersTraceSpan.js +7 -0
- package/src/index.d.ts +1032 -0
- package/src/index.js +35 -0
- package/src/logging.js +91 -0
- package/src/makeSmithersSpanAttributes.js +20 -0
- package/src/metrics/SmithersMetricDefinition.ts +17 -0
- package/src/metrics/SmithersMetricType.ts +1 -0
- package/src/metrics/SmithersMetricUnit.ts +8 -0
- package/src/metrics/_asyncExternalWaitCounts.js +4 -0
- package/src/metrics/_buckets.js +43 -0
- package/src/metrics/_processStartMs.js +1 -0
- package/src/metrics/activeNodes.js +2 -0
- package/src/metrics/activeRuns.js +2 -0
- package/src/metrics/agentActionsTotal.js +2 -0
- package/src/metrics/agentDurationMs.js +3 -0
- package/src/metrics/agentErrorsTotal.js +2 -0
- package/src/metrics/agentEventsTotal.js +2 -0
- package/src/metrics/agentInvocationsTotal.js +2 -0
- package/src/metrics/agentRetriesTotal.js +2 -0
- package/src/metrics/agentSessionsTotal.js +2 -0
- package/src/metrics/agentTokensTotal.js +2 -0
- package/src/metrics/alertDeliveriesAttempted.js +2 -0
- package/src/metrics/alertDeliveriesSuppressed.js +2 -0
- package/src/metrics/alertsAcknowledgedTotal.js +2 -0
- package/src/metrics/alertsActive.js +2 -0
- package/src/metrics/alertsEscalatedTotal.js +2 -0
- package/src/metrics/alertsFiredTotal.js +2 -0
- package/src/metrics/alertsReopenedTotal.js +2 -0
- package/src/metrics/alertsResolvedTotal.js +2 -0
- package/src/metrics/alertsSilencedTotal.js +2 -0
- package/src/metrics/approvalPending.js +2 -0
- package/src/metrics/approvalWaitDuration.js +3 -0
- package/src/metrics/approvalsDenied.js +2 -0
- package/src/metrics/approvalsGranted.js +2 -0
- package/src/metrics/approvalsRequested.js +2 -0
- package/src/metrics/attemptDuration.js +3 -0
- package/src/metrics/attentionBacklog.js +2 -0
- package/src/metrics/cacheHits.js +2 -0
- package/src/metrics/cacheMisses.js +2 -0
- package/src/metrics/dbQueryDuration.js +3 -0
- package/src/metrics/dbRetries.js +2 -0
- package/src/metrics/dbTransactionDuration.js +3 -0
- package/src/metrics/dbTransactionRetries.js +2 -0
- package/src/metrics/dbTransactionRollbacks.js +2 -0
- package/src/metrics/devtoolsActiveSubscribers.js +2 -0
- package/src/metrics/devtoolsBackpressureDisconnectTotal.js +2 -0
- package/src/metrics/devtoolsDeltaBuildMs.js +3 -0
- package/src/metrics/devtoolsEventBytes.js +3 -0
- package/src/metrics/devtoolsEventTotal.js +2 -0
- package/src/metrics/devtoolsSnapshotBuildMs.js +3 -0
- package/src/metrics/devtoolsSubscribeTotal.js +2 -0
- package/src/metrics/errorsTotal.js +2 -0
- package/src/metrics/eventsEmittedTotal.js +2 -0
- package/src/metrics/externalWaitAsyncPending.js +2 -0
- package/src/metrics/gatewayApprovalDecisionsTotal.js +2 -0
- package/src/metrics/gatewayAuthEventsTotal.js +2 -0
- package/src/metrics/gatewayConnectionsActive.js +2 -0
- package/src/metrics/gatewayConnectionsClosedTotal.js +2 -0
- package/src/metrics/gatewayConnectionsTotal.js +2 -0
- package/src/metrics/gatewayCronTriggersTotal.js +2 -0
- package/src/metrics/gatewayErrorsTotal.js +2 -0
- package/src/metrics/gatewayHeartbeatTicksTotal.js +2 -0
- package/src/metrics/gatewayMessagesReceivedTotal.js +2 -0
- package/src/metrics/gatewayMessagesSentTotal.js +2 -0
- package/src/metrics/gatewayRpcCallsTotal.js +2 -0
- package/src/metrics/gatewayRpcDuration.js +3 -0
- package/src/metrics/gatewayRunsCompletedTotal.js +2 -0
- package/src/metrics/gatewayRunsStartedTotal.js +2 -0
- package/src/metrics/gatewaySignalsTotal.js +2 -0
- package/src/metrics/gatewayWebhooksReceivedTotal.js +2 -0
- package/src/metrics/gatewayWebhooksRejectedTotal.js +2 -0
- package/src/metrics/gatewayWebhooksVerifiedTotal.js +2 -0
- package/src/metrics/heartbeatDataSizeBytes.js +3 -0
- package/src/metrics/heartbeatIntervalMs.js +3 -0
- package/src/metrics/hotReloadDuration.js +3 -0
- package/src/metrics/hotReloadFailures.js +2 -0
- package/src/metrics/hotReloads.js +2 -0
- package/src/metrics/httpRequestDuration.js +3 -0
- package/src/metrics/httpRequests.js +2 -0
- package/src/metrics/index.js +151 -0
- package/src/metrics/metricsServiceAdapter.js +188 -0
- package/src/metrics/nodeDuration.js +3 -0
- package/src/metrics/nodeRetriesTotal.js +2 -0
- package/src/metrics/nodesFailed.js +2 -0
- package/src/metrics/nodesFinished.js +2 -0
- package/src/metrics/nodesStarted.js +2 -0
- package/src/metrics/processHeapUsedBytes.js +2 -0
- package/src/metrics/processMemoryRssBytes.js +2 -0
- package/src/metrics/processUptimeSeconds.js +2 -0
- package/src/metrics/promptSizeBytes.js +3 -0
- package/src/metrics/responseSizeBytes.js +3 -0
- package/src/metrics/rewindDurationMs.js +3 -0
- package/src/metrics/rewindFramesDeleted.js +3 -0
- package/src/metrics/rewindRollbackTotal.js +2 -0
- package/src/metrics/rewindSandboxesReverted.js +3 -0
- package/src/metrics/rewindTotal.js +2 -0
- package/src/metrics/runDuration.js +3 -0
- package/src/metrics/runsAncestryDepth.js +3 -0
- package/src/metrics/runsCancelledTotal.js +2 -0
- package/src/metrics/runsCarriedStateBytes.js +3 -0
- package/src/metrics/runsContinuedTotal.js +2 -0
- package/src/metrics/runsFailedTotal.js +2 -0
- package/src/metrics/runsFinishedTotal.js +2 -0
- package/src/metrics/runsResumedTotal.js +2 -0
- package/src/metrics/runsTotal.js +2 -0
- package/src/metrics/sandboxActive.js +2 -0
- package/src/metrics/sandboxBundleSizeBytes.js +3 -0
- package/src/metrics/sandboxCompletedTotal.js +2 -0
- package/src/metrics/sandboxCreatedTotal.js +2 -0
- package/src/metrics/sandboxDurationMs.js +3 -0
- package/src/metrics/sandboxPatchCount.js +3 -0
- package/src/metrics/sandboxTransportDurationMs.js +3 -0
- package/src/metrics/schedulerConcurrencyUtilization.js +2 -0
- package/src/metrics/schedulerQueueDepth.js +2 -0
- package/src/metrics/schedulerWaitDuration.js +3 -0
- package/src/metrics/scorerEventsFailed.js +2 -0
- package/src/metrics/scorerEventsFinished.js +2 -0
- package/src/metrics/scorerEventsStarted.js +2 -0
- package/src/metrics/smithersMetricCatalog.js +484 -0
- package/src/metrics/smithersMetricCatalogByKey.js +2 -0
- package/src/metrics/smithersMetricCatalogByName.js +2 -0
- package/src/metrics/smithersMetricCatalogByPrometheusName.js +2 -0
- package/src/metrics/supervisorPollDuration.js +3 -0
- package/src/metrics/supervisorPollsTotal.js +2 -0
- package/src/metrics/supervisorResumeLag.js +3 -0
- package/src/metrics/supervisorResumedTotal.js +2 -0
- package/src/metrics/supervisorSkippedTotal.js +2 -0
- package/src/metrics/supervisorStaleDetected.js +2 -0
- package/src/metrics/taskHeartbeatTimeoutTotal.js +2 -0
- package/src/metrics/taskHeartbeatsTotal.js +2 -0
- package/src/metrics/timerDelayDuration.js +3 -0
- package/src/metrics/timersCancelled.js +2 -0
- package/src/metrics/timersCreated.js +2 -0
- package/src/metrics/timersFired.js +2 -0
- package/src/metrics/timersPending.js +2 -0
- package/src/metrics/toPrometheusMetricName.js +8 -0
- package/src/metrics/tokensCacheReadTotal.js +2 -0
- package/src/metrics/tokensCacheWriteTotal.js +2 -0
- package/src/metrics/tokensContextWindowBucketTotal.js +2 -0
- package/src/metrics/tokensContextWindowPerCall.js +3 -0
- package/src/metrics/tokensInputPerCall.js +3 -0
- package/src/metrics/tokensInputTotal.js +2 -0
- package/src/metrics/tokensOutputPerCall.js +3 -0
- package/src/metrics/tokensOutputTotal.js +2 -0
- package/src/metrics/tokensReasoningTotal.js +2 -0
- package/src/metrics/toolCallErrorsTotal.js +2 -0
- package/src/metrics/toolCallsTotal.js +2 -0
- package/src/metrics/toolDuration.js +3 -0
- package/src/metrics/toolOutputTruncatedTotal.js +2 -0
- package/src/metrics/trackEvent.js +604 -0
- package/src/metrics/updateAsyncExternalWaitPending.js +14 -0
- package/src/metrics/updateProcessMetrics.js +17 -0
- package/src/metrics/vcsDuration.js +3 -0
- package/src/prometheusContentType.js +1 -0
- package/src/renderPrometheusMetrics.js +205 -0
- package/src/resolveSmithersObservabilityOptions.js +79 -0
- package/src/smithersMetrics.js +2 -0
- package/src/smithersSpanNames.js +6 -0
- package/src/withSmithersSpan.js +15 -0
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
|
|
2
|
+
/** @typedef {import("./_corePrometheusShape.ts").MetricLabels} MetricLabels */
|
|
3
|
+
/** @typedef {import("./_corePrometheusShape.ts").PrometheusSample} PrometheusSample */
|
|
4
|
+
export {};
|
|
5
|
+
/**
|
|
6
|
+
* @param {string} name
|
|
7
|
+
* @returns {string}
|
|
8
|
+
*/
|
|
9
|
+
export function toPrometheusMetricName(name) {
|
|
10
|
+
const next = name.replace(/[^a-zA-Z0-9_:]/g, "_");
|
|
11
|
+
return /^[a-zA-Z_:]/.test(next) ? next : `_${next}`;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* @param {string} text
|
|
15
|
+
* @returns {string}
|
|
16
|
+
*/
|
|
17
|
+
function escapeText(text) {
|
|
18
|
+
return text.replace(/\\/g, "\\\\").replace(/\n/g, "\\n");
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* @param {string} value
|
|
22
|
+
* @returns {string}
|
|
23
|
+
*/
|
|
24
|
+
function escapeLabelValue(value) {
|
|
25
|
+
return escapeText(value).replace(/"/g, '\\"');
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* @param {number} value
|
|
29
|
+
* @returns {string}
|
|
30
|
+
*/
|
|
31
|
+
function formatNumber(value) {
|
|
32
|
+
if (Number.isNaN(value))
|
|
33
|
+
return "NaN";
|
|
34
|
+
if (value === Number.POSITIVE_INFINITY)
|
|
35
|
+
return "+Inf";
|
|
36
|
+
if (value === Number.NEGATIVE_INFINITY)
|
|
37
|
+
return "-Inf";
|
|
38
|
+
return String(value);
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* @param {MetricLabels} labels
|
|
42
|
+
* @returns {string}
|
|
43
|
+
*/
|
|
44
|
+
function formatLabels(labels) {
|
|
45
|
+
const entries = Object.entries(labels).sort(([left], [right]) => left.localeCompare(right));
|
|
46
|
+
if (entries.length === 0)
|
|
47
|
+
return "";
|
|
48
|
+
return `{${entries
|
|
49
|
+
.map(([key, value]) => `${toPrometheusMetricName(key)}="${escapeLabelValue(String(value))}"`)
|
|
50
|
+
.join(",")}}`;
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* @param {MetricLabels} labels
|
|
54
|
+
* @param {MetricLabels} extra
|
|
55
|
+
* @returns {MetricLabels}
|
|
56
|
+
*/
|
|
57
|
+
function mergeLabels(labels, extra) {
|
|
58
|
+
return { ...labels, ...extra };
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* @param {readonly PrometheusSample[]} samples
|
|
62
|
+
* @returns {string}
|
|
63
|
+
*/
|
|
64
|
+
export function renderPrometheusSamples(samples) {
|
|
65
|
+
const grouped = new Map();
|
|
66
|
+
for (const sample of samples) {
|
|
67
|
+
const name = toPrometheusMetricName(sample.name);
|
|
68
|
+
const group = grouped.get(name) ??
|
|
69
|
+
(() => {
|
|
70
|
+
const created = { type: sample.type, lines: [] };
|
|
71
|
+
grouped.set(name, created);
|
|
72
|
+
return created;
|
|
73
|
+
})();
|
|
74
|
+
if (sample.type === "histogram") {
|
|
75
|
+
const buckets = [...(sample.buckets ?? new Map()).entries()].sort(([left], [right]) => left - right);
|
|
76
|
+
for (const [boundary, count] of buckets) {
|
|
77
|
+
group.lines.push(`${name}_bucket${formatLabels(mergeLabels(sample.labels, { le: boundary }))} ${formatNumber(count)}`);
|
|
78
|
+
}
|
|
79
|
+
group.lines.push(`${name}_bucket${formatLabels(mergeLabels(sample.labels, { le: "+Inf" }))} ${formatNumber(sample.count ?? 0)}`);
|
|
80
|
+
group.lines.push(`${name}_sum${formatLabels(sample.labels)} ${formatNumber(sample.sum ?? 0)}`);
|
|
81
|
+
group.lines.push(`${name}_count${formatLabels(sample.labels)} ${formatNumber(sample.count ?? 0)}`);
|
|
82
|
+
}
|
|
83
|
+
else {
|
|
84
|
+
group.lines.push(`${name}${formatLabels(sample.labels)} ${formatNumber(sample.value ?? 0)}`);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
const lines = [];
|
|
88
|
+
for (const [name, group] of [...grouped.entries()].sort(([left], [right]) => left.localeCompare(right))) {
|
|
89
|
+
lines.push(`# TYPE ${name} ${group.type}`);
|
|
90
|
+
lines.push(...group.lines.sort());
|
|
91
|
+
}
|
|
92
|
+
return lines.join("\n") + (lines.length > 0 ? "\n" : "");
|
|
93
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export type MetricLabels = Readonly<Record<string, string | number | boolean>>;
|
|
2
|
+
|
|
3
|
+
export type PrometheusSample = {
|
|
4
|
+
readonly name: string;
|
|
5
|
+
readonly type: "counter" | "gauge" | "histogram";
|
|
6
|
+
readonly labels: MetricLabels;
|
|
7
|
+
readonly value?: number;
|
|
8
|
+
readonly buckets?: ReadonlyMap<number, number>;
|
|
9
|
+
readonly sum?: number;
|
|
10
|
+
readonly count?: number;
|
|
11
|
+
};
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
import { Context, Effect, Layer } from "effect";
|
|
2
|
+
import { correlationContextToLogAnnotations, getCurrentCorrelationContext, withCorrelationContext, } from "./_coreCorrelation/index.js";
|
|
3
|
+
/** @typedef {import("./SmithersLogFormat.ts").SmithersLogFormat} SmithersLogFormat */
|
|
4
|
+
/** @typedef {import("./_coreTracingShape.ts").SmithersSpanAttributesInput} SmithersSpanAttributesInput */
|
|
5
|
+
/** @typedef {import("./_coreTracingShape.ts").TracingServiceShape} TracingServiceShape */
|
|
6
|
+
|
|
7
|
+
/** @type {"text/plain; version=0.0.4; charset=utf-8"} */
|
|
8
|
+
export const prometheusContentType = "text/plain; version=0.0.4; charset=utf-8";
|
|
9
|
+
/** @type {{ readonly run: "smithers.run"; readonly task: "smithers.task"; readonly agent: "smithers.agent"; readonly tool: "smithers.tool" }} */
|
|
10
|
+
export const smithersSpanNames = {
|
|
11
|
+
run: "smithers.run",
|
|
12
|
+
task: "smithers.task",
|
|
13
|
+
agent: "smithers.agent",
|
|
14
|
+
tool: "smithers.tool",
|
|
15
|
+
};
|
|
16
|
+
const _TracingServiceBase = /** @type {Context.TagClass<TracingService, "TracingService", TracingServiceShape>} */ (/** @type {unknown} */ (Context.Tag("TracingService")()));
|
|
17
|
+
export class TracingService extends _TracingServiceBase {
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* @returns {| Readonly<Record<string, string>> | undefined}
|
|
21
|
+
*/
|
|
22
|
+
export function getCurrentSmithersTraceAnnotations() {
|
|
23
|
+
const context = getCurrentCorrelationContext();
|
|
24
|
+
if (!context?.traceId || !context.spanId)
|
|
25
|
+
return undefined;
|
|
26
|
+
return { traceId: context.traceId, spanId: context.spanId };
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* @param {SmithersSpanAttributesInput} [attributes]
|
|
30
|
+
* @returns {Record<string, unknown>}
|
|
31
|
+
*/
|
|
32
|
+
export function makeSmithersSpanAttributes(attributes = {}) {
|
|
33
|
+
const aliases = {
|
|
34
|
+
runId: "smithers.run_id",
|
|
35
|
+
run_id: "smithers.run_id",
|
|
36
|
+
workflowName: "smithers.workflow_name",
|
|
37
|
+
workflow_name: "smithers.workflow_name",
|
|
38
|
+
nodeId: "smithers.node_id",
|
|
39
|
+
node_id: "smithers.node_id",
|
|
40
|
+
iteration: "smithers.iteration",
|
|
41
|
+
attempt: "smithers.attempt",
|
|
42
|
+
nodeLabel: "smithers.node_label",
|
|
43
|
+
node_label: "smithers.node_label",
|
|
44
|
+
toolName: "smithers.tool_name",
|
|
45
|
+
tool_name: "smithers.tool_name",
|
|
46
|
+
agent: "smithers.agent",
|
|
47
|
+
model: "smithers.model",
|
|
48
|
+
status: "smithers.status",
|
|
49
|
+
waitReason: "smithers.wait_reason",
|
|
50
|
+
wait_reason: "smithers.wait_reason",
|
|
51
|
+
};
|
|
52
|
+
const result = {};
|
|
53
|
+
for (const [key, value] of Object.entries(attributes)) {
|
|
54
|
+
if (value !== undefined) {
|
|
55
|
+
result[key.startsWith("smithers.") ? key : (aliases[key] ?? key)] = value;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
return result;
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* @param {SmithersSpanAttributesInput} [attributes]
|
|
62
|
+
* @returns {attributes is SmithersSpanAttributesInput}
|
|
63
|
+
*/
|
|
64
|
+
function hasAttributes(attributes) {
|
|
65
|
+
return Boolean(attributes && Object.keys(attributes).length > 0);
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* @param {string} name
|
|
69
|
+
* @param {SmithersSpanAttributesInput} [attributes]
|
|
70
|
+
* @returns {string}
|
|
71
|
+
*/
|
|
72
|
+
function inferSmithersSpanName(name, attributes) {
|
|
73
|
+
if (name.startsWith("smithers."))
|
|
74
|
+
return name;
|
|
75
|
+
if (name.startsWith("tool:") ||
|
|
76
|
+
"toolName" in (attributes ?? {}) ||
|
|
77
|
+
"tool_name" in (attributes ?? {})) {
|
|
78
|
+
return smithersSpanNames.tool;
|
|
79
|
+
}
|
|
80
|
+
if (name.startsWith("agent:") ||
|
|
81
|
+
name.startsWith("agent.") ||
|
|
82
|
+
"agent" in (attributes ?? {})) {
|
|
83
|
+
return smithersSpanNames.agent;
|
|
84
|
+
}
|
|
85
|
+
if ("nodeId" in (attributes ?? {}) || "node_id" in (attributes ?? {})) {
|
|
86
|
+
return smithersSpanNames.task;
|
|
87
|
+
}
|
|
88
|
+
if ("runId" in (attributes ?? {}) || "run_id" in (attributes ?? {})) {
|
|
89
|
+
return smithersSpanNames.run;
|
|
90
|
+
}
|
|
91
|
+
return name;
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* @param {SmithersSpanAttributesInput} [attributes]
|
|
95
|
+
* @returns {Effect.Effect<void>}
|
|
96
|
+
*/
|
|
97
|
+
export function annotateSmithersTrace(attributes = {}) {
|
|
98
|
+
const spanAttributes = makeSmithersSpanAttributes(attributes);
|
|
99
|
+
let program = Effect.void;
|
|
100
|
+
if (Object.keys(spanAttributes).length > 0) {
|
|
101
|
+
program = program.pipe(Effect.tap(() => Effect.annotateCurrentSpan(spanAttributes).pipe(Effect.catchAll(() => Effect.void))));
|
|
102
|
+
}
|
|
103
|
+
if (hasAttributes(attributes)) {
|
|
104
|
+
program = program.pipe(Effect.annotateLogs(attributes));
|
|
105
|
+
}
|
|
106
|
+
return program;
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* @template A, E, R
|
|
110
|
+
* @param {string} name
|
|
111
|
+
* @param {Effect.Effect<A, E, R>} effect
|
|
112
|
+
* @param {SmithersSpanAttributesInput} [attributes]
|
|
113
|
+
* @returns {Effect.Effect<A, E, R>}
|
|
114
|
+
*/
|
|
115
|
+
export function withSmithersSpan(name, effect, attributes) {
|
|
116
|
+
const spanAttributes = makeSmithersSpanAttributes(attributes);
|
|
117
|
+
const annotations = correlationContextToLogAnnotations(getCurrentCorrelationContext());
|
|
118
|
+
let program = effect;
|
|
119
|
+
if (Object.keys(spanAttributes).length > 0) {
|
|
120
|
+
program = program.pipe(Effect.annotateSpans(spanAttributes));
|
|
121
|
+
}
|
|
122
|
+
if (hasAttributes(attributes)) {
|
|
123
|
+
program = program.pipe(Effect.annotateLogs(attributes));
|
|
124
|
+
}
|
|
125
|
+
if (annotations) {
|
|
126
|
+
program = program.pipe(Effect.annotateLogs(annotations));
|
|
127
|
+
}
|
|
128
|
+
return program.pipe(Effect.withLogSpan(name), Effect.withSpan(inferSmithersSpanName(name, attributes)));
|
|
129
|
+
}
|
|
130
|
+
/** @type {Layer.Layer<TracingService, never, never>} */
|
|
131
|
+
export const TracingServiceLive = Layer.succeed(TracingService, {
|
|
132
|
+
withSpan: (name, effect, attributes) => {
|
|
133
|
+
return withSmithersSpan(name, effect, attributes);
|
|
134
|
+
},
|
|
135
|
+
annotate: (attributes) => {
|
|
136
|
+
const spanAttributes = makeSmithersSpanAttributes(attributes);
|
|
137
|
+
return Object.keys(spanAttributes).length > 0
|
|
138
|
+
? Effect.annotateCurrentSpan(spanAttributes).pipe(Effect.catchAll(() => Effect.void))
|
|
139
|
+
: Effect.void;
|
|
140
|
+
},
|
|
141
|
+
withCorrelation: (context, effect) => withCorrelationContext(effect, context),
|
|
142
|
+
});
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { Effect } from "effect";
|
|
2
|
+
import type { CorrelationPatch } from "./_coreCorrelation/CorrelationPatch.ts";
|
|
3
|
+
|
|
4
|
+
export type SmithersSpanAttributesInput = Readonly<Record<string, unknown>>;
|
|
5
|
+
|
|
6
|
+
export type TracingServiceShape = {
|
|
7
|
+
readonly withSpan: <A, E, R>(
|
|
8
|
+
name: string,
|
|
9
|
+
effect: Effect.Effect<A, E, R>,
|
|
10
|
+
attributes?: Record<string, unknown>,
|
|
11
|
+
) => Effect.Effect<A, E, R>;
|
|
12
|
+
readonly annotate: (attributes: Record<string, unknown>) => Effect.Effect<void>;
|
|
13
|
+
readonly withCorrelation: <A, E, R>(
|
|
14
|
+
context: CorrelationPatch,
|
|
15
|
+
effect: Effect.Effect<A, E, R>,
|
|
16
|
+
) => Effect.Effect<A, E, R>;
|
|
17
|
+
};
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export const smithersSpanAttributeAliases = {
|
|
2
|
+
runId: "smithers.run_id",
|
|
3
|
+
run_id: "smithers.run_id",
|
|
4
|
+
workflowName: "smithers.workflow_name",
|
|
5
|
+
workflow_name: "smithers.workflow_name",
|
|
6
|
+
nodeId: "smithers.node_id",
|
|
7
|
+
node_id: "smithers.node_id",
|
|
8
|
+
iteration: "smithers.iteration",
|
|
9
|
+
attempt: "smithers.attempt",
|
|
10
|
+
nodeLabel: "smithers.node_label",
|
|
11
|
+
node_label: "smithers.node_label",
|
|
12
|
+
toolName: "smithers.tool_name",
|
|
13
|
+
tool_name: "smithers.tool_name",
|
|
14
|
+
agent: "smithers.agent",
|
|
15
|
+
model: "smithers.model",
|
|
16
|
+
status: "smithers.status",
|
|
17
|
+
waitReason: "smithers.wait_reason",
|
|
18
|
+
wait_reason: "smithers.wait_reason",
|
|
19
|
+
};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { TracingService, annotateSmithersTrace as annotateCoreSmithersTrace, } from "./_coreTracing.js";
|
|
2
|
+
import { Effect } from "effect";
|
|
3
|
+
/**
|
|
4
|
+
* @param {Readonly<Record<string, unknown>>} [attributes]
|
|
5
|
+
* @returns {Effect.Effect<void>}
|
|
6
|
+
*/
|
|
7
|
+
export function annotateSmithersTrace(attributes = {}) {
|
|
8
|
+
return Effect.flatMap(Effect.serviceOption(TracingService), (service) => service._tag === "Some"
|
|
9
|
+
? service.value.annotate({ ...attributes })
|
|
10
|
+
: annotateCoreSmithersTrace(attributes));
|
|
11
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { getCurrentCorrelationContext as getCoreCurrentCorrelationContext, mergeCorrelationContext as mergeCoreCorrelationContext, } from "./_coreCorrelation/index.js";
|
|
2
|
+
/** @typedef {import("./_coreCorrelation/CorrelationContext.ts").CorrelationContext} CorrelationContext */
|
|
3
|
+
/** @typedef {import("./_coreCorrelation/CorrelationPatch.ts").CorrelationPatch} CorrelationPatch */
|
|
4
|
+
/** @typedef {CorrelationPatch} CorrelationContextPatch */
|
|
5
|
+
|
|
6
|
+
export { correlationContextFiberRef, correlationContextToLogAnnotations, CorrelationContextLive, CorrelationContextService, getCurrentCorrelationContext, getCurrentCorrelationContextEffect, mergeCorrelationContext, runWithCorrelationContext, withCorrelationContext, withCurrentCorrelationContext, } from "./_coreCorrelation/index.js";
|
|
7
|
+
/**
|
|
8
|
+
* @param {CorrelationPatch} patch
|
|
9
|
+
*/
|
|
10
|
+
export function updateCurrentCorrelationContext(patch) {
|
|
11
|
+
const current = getCoreCurrentCorrelationContext();
|
|
12
|
+
if (!current)
|
|
13
|
+
return;
|
|
14
|
+
// TODO: replace this compatibility shim once legacy callers adopt the
|
|
15
|
+
// Effect-returning updateCurrentCorrelationContext from @smithers-orchestrator/observability.
|
|
16
|
+
const next = mergeCoreCorrelationContext(current, patch);
|
|
17
|
+
if (!next)
|
|
18
|
+
return;
|
|
19
|
+
Object.assign(current, next);
|
|
20
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import * as BunContext from "@effect/platform-bun/BunContext";
|
|
2
|
+
import { TracingServiceLive } from "./_coreTracing.js";
|
|
3
|
+
import { Effect, Layer, Logger } from "effect";
|
|
4
|
+
import { SmithersObservability } from "./SmithersObservability.js";
|
|
5
|
+
import { resolveSmithersObservabilityOptions } from "./resolveSmithersObservabilityOptions.js";
|
|
6
|
+
import { createSmithersOtelLayer } from "./createSmithersOtelLayer.js";
|
|
7
|
+
import { MetricsServiceLive } from "./MetricsServiceLive.js";
|
|
8
|
+
import { annotateSmithersTrace } from "./annotateSmithersTrace.js";
|
|
9
|
+
import { withSmithersSpan } from "./withSmithersSpan.js";
|
|
10
|
+
/** @typedef {import("./ResolvedSmithersObservabilityOptions.ts").ResolvedSmithersObservabilityOptions} ResolvedSmithersObservabilityOptions */
|
|
11
|
+
/** @typedef {import("./SmithersLogFormat.ts").SmithersLogFormat} SmithersLogFormat */
|
|
12
|
+
/** @typedef {import("./SmithersObservabilityService.ts").SmithersObservabilityService} SmithersObservabilityService */
|
|
13
|
+
|
|
14
|
+
/** @typedef {import("./SmithersObservabilityOptions.ts").SmithersObservabilityOptions} SmithersObservabilityOptions */
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* @param {SmithersLogFormat} format
|
|
18
|
+
*/
|
|
19
|
+
function resolveLogger(format) {
|
|
20
|
+
switch (format) {
|
|
21
|
+
case "json":
|
|
22
|
+
return Logger.withLeveledConsole(Logger.jsonLogger);
|
|
23
|
+
case "pretty":
|
|
24
|
+
return Logger.prettyLogger();
|
|
25
|
+
case "string":
|
|
26
|
+
return Logger.withLeveledConsole(Logger.stringLogger);
|
|
27
|
+
case "logfmt":
|
|
28
|
+
default:
|
|
29
|
+
return Logger.withLeveledConsole(Logger.logfmtLogger);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* @param {ResolvedSmithersObservabilityOptions} options
|
|
34
|
+
* @returns {SmithersObservabilityService}
|
|
35
|
+
*/
|
|
36
|
+
function makeService(options) {
|
|
37
|
+
return {
|
|
38
|
+
options,
|
|
39
|
+
annotate: (attributes) => annotateSmithersTrace(attributes),
|
|
40
|
+
withSpan: (name, effect, attributes) => withSmithersSpan(name, effect, attributes),
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* @param {SmithersObservabilityOptions} [options]
|
|
45
|
+
*/
|
|
46
|
+
export function createSmithersObservabilityLayer(options = {}) {
|
|
47
|
+
const resolved = resolveSmithersObservabilityOptions(options);
|
|
48
|
+
return Layer.mergeAll(BunContext.layer, Logger.replace(Logger.defaultLogger, resolveLogger(resolved.logFormat)), Logger.minimumLogLevel(resolved.logLevel), createSmithersOtelLayer(resolved), MetricsServiceLive, TracingServiceLive, Layer.succeed(SmithersObservability, makeService(resolved)));
|
|
49
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import * as FetchHttpClient from "@effect/platform/FetchHttpClient";
|
|
2
|
+
import * as Otlp from "@effect/opentelemetry/Otlp";
|
|
3
|
+
import { Layer } from "effect";
|
|
4
|
+
import { smithersTraceSpanStorage } from "./_smithersTraceSpanStorage.js";
|
|
5
|
+
import { resolveSmithersObservabilityOptions } from "./resolveSmithersObservabilityOptions.js";
|
|
6
|
+
/** @typedef {import("./SmithersObservabilityOptions.ts").SmithersObservabilityOptions} SmithersObservabilityOptions */
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* @param {SmithersObservabilityOptions} [options]
|
|
10
|
+
*/
|
|
11
|
+
export function createSmithersOtelLayer(options = {}) {
|
|
12
|
+
const resolved = resolveSmithersObservabilityOptions(options);
|
|
13
|
+
if (!resolved.enabled) {
|
|
14
|
+
return Layer.empty;
|
|
15
|
+
}
|
|
16
|
+
return Otlp.layerJson({
|
|
17
|
+
baseUrl: resolved.endpoint,
|
|
18
|
+
resource: { serviceName: resolved.serviceName },
|
|
19
|
+
tracerContext: (execute, span) => smithersTraceSpanStorage.run(span, execute),
|
|
20
|
+
}).pipe(Layer.provide(FetchHttpClient.layer));
|
|
21
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { getCurrentSmithersTraceSpan } from "./getCurrentSmithersTraceSpan.js";
|
|
2
|
+
/**
|
|
3
|
+
* @returns {| Readonly<Record<string, string>> | undefined}
|
|
4
|
+
*/
|
|
5
|
+
export function getCurrentSmithersTraceAnnotations() {
|
|
6
|
+
const span = getCurrentSmithersTraceSpan();
|
|
7
|
+
if (!span) {
|
|
8
|
+
return undefined;
|
|
9
|
+
}
|
|
10
|
+
return {
|
|
11
|
+
traceId: span.traceId,
|
|
12
|
+
spanId: span.spanId,
|
|
13
|
+
};
|
|
14
|
+
}
|