MCPcopy Create free account
hub / github.com/ShipSecAI/studio / LokiLogAdapter

Class LokiLogAdapter

worker/src/adapters/loki-log.adapter.ts:83–263  ·  view source on GitHub ↗

Source from the content-addressed store, hash-verified

81}
82
83export class LokiLogAdapter implements WorkflowLogSink {
84 constructor(
85 private readonly client: LokiPushClient,
86 private readonly db?: NodePgDatabase<typeof schema>,
87 ) {}
88 private ensureIndexPromise?: Promise<void>;
89
90 async append(entry: WorkflowLogEntry): Promise<void> {
91 if (!entry.message || entry.message.trim().length === 0) {
92 return;
93 }
94
95 const timestamp = entry.timestamp ?? new Date();
96 const labels = this.buildLabels(entry);
97 const lines = this.buildLines(entry.message, timestamp);
98 const lineCount = lines.length;
99
100 try {
101 await this.client.push(labels, lines);
102 } catch (error) {
103 console.error('[LOKI] Failed to push log entry', error);
104 return;
105 }
106
107 if (this.db) {
108 await this.persistMetadata({
109 runId: entry.runId,
110 nodeRef: entry.nodeRef,
111 stream: entry.stream,
112 labels,
113 lineCount,
114 timestamp,
115 organizationId: entry.organizationId ?? null,
116 });
117 }
118 }
119
120 private buildLabels(entry: WorkflowLogEntry): Record<string, string> {
121 const labels: Record<string, string> = {
122 run_id: entry.runId,
123 node: entry.nodeRef,
124 stream: entry.stream,
125 };
126
127 if (entry.level) {
128 labels.level = entry.level;
129 }
130
131 if (entry.metadata?.activityId) {
132 labels.activity_id = entry.metadata.activityId;
133 }
134
135 if (entry.metadata?.attempt !== undefined) {
136 labels.attempt = String(entry.metadata.attempt);
137 }
138
139 if (entry.metadata?.correlationId) {
140 labels.correlation_id = entry.metadata.correlationId;

Callers

nothing calls this directly

Calls

no outgoing calls

Tested by

no test coverage detected