@neat.is/core 0.3.6 → 0.3.8
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/dist/{chunk-4ASCXBZF.js → chunk-7TYESDAI.js} +101 -5
- package/dist/chunk-7TYESDAI.js.map +1 -0
- package/dist/{chunk-ZU2RQRCN.js → chunk-CZ3T6TE2.js} +251 -245
- package/dist/{chunk-ZU2RQRCN.js.map → chunk-CZ3T6TE2.js.map} +1 -1
- package/dist/{chunk-YHQYHFI3.js → chunk-LQ3JFBTX.js} +99 -17
- package/dist/chunk-LQ3JFBTX.js.map +1 -0
- package/dist/{chunk-G3PDTGOW.js → chunk-V4TU7OKZ.js} +16 -2
- package/dist/chunk-V4TU7OKZ.js.map +1 -0
- package/dist/cli.cjs +1264 -396
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.d.cts +5 -0
- package/dist/cli.d.ts +5 -0
- package/dist/cli.js +935 -153
- package/dist/cli.js.map +1 -1
- package/dist/index.cjs +215 -18
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +29 -0
- package/dist/index.d.ts +29 -0
- package/dist/index.js +4 -4
- package/dist/neatd.cjs +228 -19
- package/dist/neatd.cjs.map +1 -1
- package/dist/neatd.js +14 -4
- package/dist/neatd.js.map +1 -1
- package/dist/{otel-grpc-J4O2SIBZ.js → otel-grpc-S3AENOZ6.js} +3 -3
- package/dist/server.cjs +143 -10
- package/dist/server.cjs.map +1 -1
- package/dist/server.js +25 -7
- package/dist/server.js.map +1 -1
- package/package.json +2 -2
- package/dist/chunk-4ASCXBZF.js.map +0 -1
- package/dist/chunk-G3PDTGOW.js.map +0 -1
- package/dist/chunk-YHQYHFI3.js.map +0 -1
- /package/dist/{otel-grpc-J4O2SIBZ.js.map → otel-grpc-S3AENOZ6.js.map} +0 -0
package/dist/index.cjs
CHANGED
|
@@ -40,6 +40,75 @@ var init_cjs_shims = __esm({
|
|
|
40
40
|
}
|
|
41
41
|
});
|
|
42
42
|
|
|
43
|
+
// src/auth.ts
|
|
44
|
+
function isLoopbackHost(host) {
|
|
45
|
+
if (!host) return false;
|
|
46
|
+
return LOOPBACK_HOSTS.has(host);
|
|
47
|
+
}
|
|
48
|
+
function assertBindAuthority(host, token) {
|
|
49
|
+
if (token && token.length > 0) return;
|
|
50
|
+
if (isLoopbackHost(host)) return;
|
|
51
|
+
throw new BindAuthorityError(host);
|
|
52
|
+
}
|
|
53
|
+
function mountBearerAuth(app, opts) {
|
|
54
|
+
if (!opts.token || opts.token.length === 0) return;
|
|
55
|
+
if (opts.trustProxy) return;
|
|
56
|
+
const expected = Buffer.from(opts.token, "utf8");
|
|
57
|
+
const suffixes = [...DEFAULT_UNAUTH_SUFFIXES, ...opts.extraUnauthenticatedSuffixes ?? []];
|
|
58
|
+
app.addHook("preHandler", (req, reply, done) => {
|
|
59
|
+
const path37 = (req.url.split("?")[0] ?? "").replace(/\/+$/, "");
|
|
60
|
+
for (const suffix of suffixes) {
|
|
61
|
+
if (path37 === suffix || path37.endsWith(suffix)) {
|
|
62
|
+
done();
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
const header = req.headers.authorization;
|
|
67
|
+
if (typeof header !== "string" || !header.startsWith("Bearer ")) {
|
|
68
|
+
void reply.code(401).send({ error: "unauthorized" });
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
const provided = Buffer.from(header.slice("Bearer ".length).trim(), "utf8");
|
|
72
|
+
if (provided.length !== expected.length || !(0, import_node_crypto.timingSafeEqual)(provided, expected)) {
|
|
73
|
+
void reply.code(401).send({ error: "unauthorized" });
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
done();
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
function readAuthEnv(env = process.env) {
|
|
80
|
+
const t = env.NEAT_AUTH_TOKEN;
|
|
81
|
+
const ot = env.NEAT_OTEL_TOKEN;
|
|
82
|
+
return {
|
|
83
|
+
authToken: t && t.length > 0 ? t : void 0,
|
|
84
|
+
otelToken: ot && ot.length > 0 ? ot : t && t.length > 0 ? t : void 0,
|
|
85
|
+
trustProxy: env.NEAT_AUTH_PROXY === "true"
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
var import_node_crypto, LOOPBACK_HOSTS, BindAuthorityError, DEFAULT_UNAUTH_SUFFIXES;
|
|
89
|
+
var init_auth = __esm({
|
|
90
|
+
"src/auth.ts"() {
|
|
91
|
+
"use strict";
|
|
92
|
+
init_cjs_shims();
|
|
93
|
+
import_node_crypto = require("crypto");
|
|
94
|
+
LOOPBACK_HOSTS = /* @__PURE__ */ new Set([
|
|
95
|
+
"127.0.0.1",
|
|
96
|
+
"localhost",
|
|
97
|
+
"::1",
|
|
98
|
+
"::ffff:127.0.0.1"
|
|
99
|
+
]);
|
|
100
|
+
BindAuthorityError = class extends Error {
|
|
101
|
+
constructor(host) {
|
|
102
|
+
super(
|
|
103
|
+
`NEAT refuses to bind on a public interface without \`NEAT_AUTH_TOKEN\` set (host="${host}"). Set the token or bind to loopback only.`
|
|
104
|
+
);
|
|
105
|
+
this.name = "BindAuthorityError";
|
|
106
|
+
}
|
|
107
|
+
};
|
|
108
|
+
DEFAULT_UNAUTH_SUFFIXES = ["/health", "/healthz", "/readyz"];
|
|
109
|
+
}
|
|
110
|
+
});
|
|
111
|
+
|
|
43
112
|
// src/otel-grpc.ts
|
|
44
113
|
var otel_grpc_exports = {};
|
|
45
114
|
__export(otel_grpc_exports, {
|
|
@@ -122,8 +191,21 @@ function loadTraceService() {
|
|
|
122
191
|
async function startOtelGrpcReceiver(opts) {
|
|
123
192
|
const server = new grpc.Server();
|
|
124
193
|
const service = loadTraceService();
|
|
194
|
+
const requiresAuth = !opts.trustProxy && !!opts.authToken && opts.authToken.length > 0;
|
|
195
|
+
const expectedHeader = requiresAuth ? `Bearer ${opts.authToken}` : "";
|
|
125
196
|
server.addService(service, {
|
|
126
197
|
Export: (call, callback) => {
|
|
198
|
+
if (requiresAuth) {
|
|
199
|
+
const meta = call.metadata.get("authorization");
|
|
200
|
+
const got = meta.length > 0 ? String(meta[0]) : "";
|
|
201
|
+
const a = Buffer.from(got, "utf8");
|
|
202
|
+
const b = Buffer.from(expectedHeader, "utf8");
|
|
203
|
+
const ok = a.length === b.length && (0, import_node_crypto2.timingSafeEqual)(a, b);
|
|
204
|
+
if (!ok) {
|
|
205
|
+
callback({ code: grpc.status.UNAUTHENTICATED, message: "unauthorized" });
|
|
206
|
+
return;
|
|
207
|
+
}
|
|
208
|
+
}
|
|
127
209
|
void (async () => {
|
|
128
210
|
try {
|
|
129
211
|
const reshaped = reshapeGrpcRequest(call.request ?? {});
|
|
@@ -156,13 +238,14 @@ async function startOtelGrpcReceiver(opts) {
|
|
|
156
238
|
})
|
|
157
239
|
};
|
|
158
240
|
}
|
|
159
|
-
var import_node_url, import_node_path34, grpc, protoLoader;
|
|
241
|
+
var import_node_url, import_node_path34, import_node_crypto2, grpc, protoLoader;
|
|
160
242
|
var init_otel_grpc = __esm({
|
|
161
243
|
"src/otel-grpc.ts"() {
|
|
162
244
|
"use strict";
|
|
163
245
|
init_cjs_shims();
|
|
164
246
|
import_node_url = require("url");
|
|
165
247
|
import_node_path34 = __toESM(require("path"), 1);
|
|
248
|
+
import_node_crypto2 = require("crypto");
|
|
166
249
|
grpc = __toESM(require("@grpc/grpc-js"), 1);
|
|
167
250
|
protoLoader = __toESM(require("@grpc/proto-loader"), 1);
|
|
168
251
|
init_otel();
|
|
@@ -257,8 +340,7 @@ function parseOtlpRequest(body) {
|
|
|
257
340
|
}
|
|
258
341
|
return out;
|
|
259
342
|
}
|
|
260
|
-
function
|
|
261
|
-
if (exportTraceServiceRequestType) return exportTraceServiceRequestType;
|
|
343
|
+
function loadProtoRoot() {
|
|
262
344
|
const here = import_node_path35.default.dirname((0, import_node_url2.fileURLToPath)(importMetaUrl));
|
|
263
345
|
const protoRoot = import_node_path35.default.resolve(here, "..", "proto");
|
|
264
346
|
const root = new import_protobufjs.default.Root();
|
|
@@ -267,11 +349,32 @@ function loadProtobufDecoder() {
|
|
|
267
349
|
"opentelemetry/proto/collector/trace/v1/trace_service.proto",
|
|
268
350
|
{ keepCase: true }
|
|
269
351
|
);
|
|
352
|
+
return root;
|
|
353
|
+
}
|
|
354
|
+
function loadProtobufDecoder() {
|
|
355
|
+
if (exportTraceServiceRequestType) return exportTraceServiceRequestType;
|
|
356
|
+
const root = loadProtoRoot();
|
|
270
357
|
exportTraceServiceRequestType = root.lookupType(
|
|
271
358
|
"opentelemetry.proto.collector.trace.v1.ExportTraceServiceRequest"
|
|
272
359
|
);
|
|
273
360
|
return exportTraceServiceRequestType;
|
|
274
361
|
}
|
|
362
|
+
function loadProtobufResponseEncoder() {
|
|
363
|
+
if (exportTraceServiceResponseType) return exportTraceServiceResponseType;
|
|
364
|
+
const root = loadProtoRoot();
|
|
365
|
+
exportTraceServiceResponseType = root.lookupType(
|
|
366
|
+
"opentelemetry.proto.collector.trace.v1.ExportTraceServiceResponse"
|
|
367
|
+
);
|
|
368
|
+
return exportTraceServiceResponseType;
|
|
369
|
+
}
|
|
370
|
+
function encodeProtobufResponseBody() {
|
|
371
|
+
if (cachedProtobufResponseBody) return cachedProtobufResponseBody;
|
|
372
|
+
const Type = loadProtobufResponseEncoder();
|
|
373
|
+
const msg = Type.create({});
|
|
374
|
+
const encoded = Type.encode(msg).finish();
|
|
375
|
+
cachedProtobufResponseBody = Buffer.from(encoded);
|
|
376
|
+
return cachedProtobufResponseBody;
|
|
377
|
+
}
|
|
275
378
|
async function decodeProtobufBody(buf) {
|
|
276
379
|
const Type = loadProtobufDecoder();
|
|
277
380
|
const decoded = Type.decode(buf).toJSON();
|
|
@@ -283,6 +386,7 @@ async function buildOtelReceiver(opts) {
|
|
|
283
386
|
logger: false,
|
|
284
387
|
bodyLimit: opts.bodyLimit ?? 16 * 1024 * 1024
|
|
285
388
|
});
|
|
389
|
+
mountBearerAuth(app, { token: opts.authToken, trustProxy: opts.trustProxy });
|
|
286
390
|
const queue = [];
|
|
287
391
|
let draining = false;
|
|
288
392
|
let drainPromise = Promise.resolve();
|
|
@@ -318,7 +422,9 @@ async function buildOtelReceiver(opts) {
|
|
|
318
422
|
app.post("/v1/traces", async (req, reply) => {
|
|
319
423
|
const ct = (req.headers["content-type"] ?? "").toString().split(";")[0].trim().toLowerCase();
|
|
320
424
|
let body;
|
|
425
|
+
let responseFlavor;
|
|
321
426
|
if (ct === "application/x-protobuf") {
|
|
427
|
+
responseFlavor = "protobuf";
|
|
322
428
|
try {
|
|
323
429
|
body = await decodeProtobufBody(req.body);
|
|
324
430
|
} catch (err) {
|
|
@@ -327,6 +433,7 @@ async function buildOtelReceiver(opts) {
|
|
|
327
433
|
});
|
|
328
434
|
}
|
|
329
435
|
} else if (!ct || ct === "application/json") {
|
|
436
|
+
responseFlavor = "json";
|
|
330
437
|
body = req.body ?? {};
|
|
331
438
|
} else {
|
|
332
439
|
return reply.code(415).send({ error: `unsupported content-type: ${ct}` });
|
|
@@ -344,7 +451,11 @@ async function buildOtelReceiver(opts) {
|
|
|
344
451
|
}
|
|
345
452
|
}
|
|
346
453
|
enqueue(spans);
|
|
347
|
-
|
|
454
|
+
if (responseFlavor === "protobuf") {
|
|
455
|
+
const buf = encodeProtobufResponseBody();
|
|
456
|
+
return reply.code(200).header("content-type", "application/x-protobuf").send(buf);
|
|
457
|
+
}
|
|
458
|
+
return reply.code(200).header("content-type", "application/json").send({ partialSuccess: {} });
|
|
348
459
|
});
|
|
349
460
|
const decorated = app;
|
|
350
461
|
decorated.flushPending = async () => {
|
|
@@ -362,7 +473,7 @@ function logSpanHandler(span) {
|
|
|
362
473
|
`otel: ${span.service} ${span.name} parent=${parent} status=${status2}${db}`
|
|
363
474
|
);
|
|
364
475
|
}
|
|
365
|
-
var import_node_path35, import_node_url2, import_fastify2, import_protobufjs, exportTraceServiceRequestType;
|
|
476
|
+
var import_node_path35, import_node_url2, import_fastify2, import_protobufjs, exportTraceServiceRequestType, exportTraceServiceResponseType, cachedProtobufResponseBody;
|
|
366
477
|
var init_otel = __esm({
|
|
367
478
|
"src/otel.ts"() {
|
|
368
479
|
"use strict";
|
|
@@ -371,7 +482,10 @@ var init_otel = __esm({
|
|
|
371
482
|
import_node_url2 = require("url");
|
|
372
483
|
import_fastify2 = __toESM(require("fastify"), 1);
|
|
373
484
|
import_protobufjs = __toESM(require("protobufjs"), 1);
|
|
485
|
+
init_auth();
|
|
374
486
|
exportTraceServiceRequestType = null;
|
|
487
|
+
exportTraceServiceResponseType = null;
|
|
488
|
+
cachedProtobufResponseBody = null;
|
|
375
489
|
}
|
|
376
490
|
});
|
|
377
491
|
|
|
@@ -4814,6 +4928,7 @@ data: ${JSON.stringify(envelope.payload)}
|
|
|
4814
4928
|
}
|
|
4815
4929
|
|
|
4816
4930
|
// src/api.ts
|
|
4931
|
+
init_auth();
|
|
4817
4932
|
function serializeGraph(graph) {
|
|
4818
4933
|
const nodes = [];
|
|
4819
4934
|
graph.forEachNode((_id, attrs) => {
|
|
@@ -5179,6 +5294,7 @@ function registerRoutes(scope, ctx) {
|
|
|
5179
5294
|
async function buildApi(opts) {
|
|
5180
5295
|
const app = (0, import_fastify.default)({ logger: false });
|
|
5181
5296
|
await app.register(import_cors.default, { origin: true });
|
|
5297
|
+
mountBearerAuth(app, { token: opts.authToken, trustProxy: opts.trustProxy });
|
|
5182
5298
|
const startedAt = opts.startedAt ?? Date.now();
|
|
5183
5299
|
const registry = buildLegacyRegistry(opts);
|
|
5184
5300
|
const legacyErrorsExplicit = !opts.projects && opts.errorsPath !== void 0;
|
|
@@ -5249,6 +5365,7 @@ init_cjs_shims();
|
|
|
5249
5365
|
var import_node_fs21 = require("fs");
|
|
5250
5366
|
var import_node_path36 = __toESM(require("path"), 1);
|
|
5251
5367
|
init_otel();
|
|
5368
|
+
init_auth();
|
|
5252
5369
|
function neatHomeFor(opts) {
|
|
5253
5370
|
if (opts.neatHome && opts.neatHome.length > 0) return import_node_path36.default.resolve(opts.neatHome);
|
|
5254
5371
|
const env = process.env.NEAT_HOME;
|
|
@@ -5259,13 +5376,35 @@ function neatHomeFor(opts) {
|
|
|
5259
5376
|
function routeSpanToProject(serviceName, projects) {
|
|
5260
5377
|
if (!serviceName) return DEFAULT_PROJECT;
|
|
5261
5378
|
for (const entry of projects) {
|
|
5262
|
-
if (entry.status
|
|
5263
|
-
if (entry.languages.length === 0) {
|
|
5264
|
-
}
|
|
5379
|
+
if (entry.status === "paused") continue;
|
|
5265
5380
|
if (entry.name === serviceName) return entry.name;
|
|
5266
5381
|
}
|
|
5382
|
+
const candidates = [];
|
|
5383
|
+
for (const entry of projects) {
|
|
5384
|
+
if (entry.status === "paused") continue;
|
|
5385
|
+
if (isTokenPrefix(entry.name, serviceName)) candidates.push(entry);
|
|
5386
|
+
}
|
|
5387
|
+
if (candidates.length > 0) {
|
|
5388
|
+
candidates.sort((a, b) => b.name.length - a.name.length);
|
|
5389
|
+
return candidates[0].name;
|
|
5390
|
+
}
|
|
5391
|
+
for (const entry of projects) {
|
|
5392
|
+
if (entry.status === "paused") continue;
|
|
5393
|
+
if (isTokenContained(entry.name, serviceName)) return entry.name;
|
|
5394
|
+
}
|
|
5267
5395
|
return DEFAULT_PROJECT;
|
|
5268
5396
|
}
|
|
5397
|
+
function isTokenPrefix(prefix, full) {
|
|
5398
|
+
if (prefix.length >= full.length) return false;
|
|
5399
|
+
if (!full.startsWith(prefix)) return false;
|
|
5400
|
+
const sep = full.charAt(prefix.length);
|
|
5401
|
+
return sep === "-" || sep === "_";
|
|
5402
|
+
}
|
|
5403
|
+
function isTokenContained(needle, haystack) {
|
|
5404
|
+
if (!haystack.includes(needle)) return false;
|
|
5405
|
+
const tokens = haystack.split(/[-_]/);
|
|
5406
|
+
return tokens.includes(needle);
|
|
5407
|
+
}
|
|
5269
5408
|
async function bootstrapProject(entry) {
|
|
5270
5409
|
const paths = pathsForProject(entry.name, import_node_path36.default.join(entry.path, "neat-out"));
|
|
5271
5410
|
try {
|
|
@@ -5345,6 +5484,17 @@ async function startDaemon(opts = {}) {
|
|
|
5345
5484
|
`);
|
|
5346
5485
|
const slots = /* @__PURE__ */ new Map();
|
|
5347
5486
|
const registry = new Projects();
|
|
5487
|
+
const DROP_WARN_INTERVAL_MS = 6e4;
|
|
5488
|
+
const lastDropWarnAt = /* @__PURE__ */ new Map();
|
|
5489
|
+
function warnDroppedSpan(project, reason) {
|
|
5490
|
+
const now = Date.now();
|
|
5491
|
+
const prev = lastDropWarnAt.get(project) ?? 0;
|
|
5492
|
+
if (now - prev < DROP_WARN_INTERVAL_MS) return;
|
|
5493
|
+
lastDropWarnAt.set(project, now);
|
|
5494
|
+
console.warn(
|
|
5495
|
+
`[neatd] dropping span for project "${project}" \u2014 project status: broken (${reason}). Run \`neatd reload\` to retry bootstrap.`
|
|
5496
|
+
);
|
|
5497
|
+
}
|
|
5348
5498
|
function upsertRegistryFromSlot(slot) {
|
|
5349
5499
|
if (slot.status !== "active") return;
|
|
5350
5500
|
registry.set(slot.entry.name, {
|
|
@@ -5353,12 +5503,38 @@ async function startDaemon(opts = {}) {
|
|
|
5353
5503
|
graph: slot.graph
|
|
5354
5504
|
});
|
|
5355
5505
|
}
|
|
5506
|
+
async function tryRecoverSlot(entry) {
|
|
5507
|
+
try {
|
|
5508
|
+
const fresh = await bootstrapProject(entry);
|
|
5509
|
+
slots.set(entry.name, fresh);
|
|
5510
|
+
upsertRegistryFromSlot(fresh);
|
|
5511
|
+
if (fresh.status === "active") {
|
|
5512
|
+
await setStatus(entry.name, "active").catch(() => {
|
|
5513
|
+
});
|
|
5514
|
+
console.log(
|
|
5515
|
+
`neatd: project "${entry.name}" recovered from broken \u2014 active`
|
|
5516
|
+
);
|
|
5517
|
+
}
|
|
5518
|
+
return fresh;
|
|
5519
|
+
} catch (err) {
|
|
5520
|
+
console.warn(
|
|
5521
|
+
`neatd: project "${entry.name}" still broken after recovery attempt \u2014 ${err.message}`
|
|
5522
|
+
);
|
|
5523
|
+
return slots.get(entry.name);
|
|
5524
|
+
}
|
|
5525
|
+
}
|
|
5356
5526
|
async function loadAll() {
|
|
5357
5527
|
const projects = await listProjects();
|
|
5358
5528
|
const seen = /* @__PURE__ */ new Set();
|
|
5359
5529
|
for (const entry of projects) {
|
|
5360
5530
|
seen.add(entry.name);
|
|
5361
|
-
|
|
5531
|
+
const existing = slots.get(entry.name);
|
|
5532
|
+
if (existing) {
|
|
5533
|
+
if (existing.status === "broken") {
|
|
5534
|
+
await tryRecoverSlot(entry);
|
|
5535
|
+
}
|
|
5536
|
+
continue;
|
|
5537
|
+
}
|
|
5362
5538
|
try {
|
|
5363
5539
|
const slot = await bootstrapProject(entry);
|
|
5364
5540
|
slots.set(entry.name, slot);
|
|
@@ -5396,8 +5572,14 @@ async function startDaemon(opts = {}) {
|
|
|
5396
5572
|
const host = resolveHost(opts);
|
|
5397
5573
|
const restPort = resolveRestPort(opts);
|
|
5398
5574
|
const otlpPort = resolveOtlpPort(opts);
|
|
5575
|
+
const auth = readAuthEnv();
|
|
5576
|
+
assertBindAuthority(host, auth.authToken);
|
|
5399
5577
|
try {
|
|
5400
|
-
restApp = await buildApi({
|
|
5578
|
+
restApp = await buildApi({
|
|
5579
|
+
projects: registry,
|
|
5580
|
+
authToken: auth.authToken,
|
|
5581
|
+
trustProxy: auth.trustProxy
|
|
5582
|
+
});
|
|
5401
5583
|
restAddress = await restApp.listen({ port: restPort, host });
|
|
5402
5584
|
console.log(`neatd: REST listening on ${restAddress}`);
|
|
5403
5585
|
} catch (err) {
|
|
@@ -5415,13 +5597,30 @@ async function startDaemon(opts = {}) {
|
|
|
5415
5597
|
`neatd: failed to bind REST on port ${restPort} \u2014 ${err.message}`
|
|
5416
5598
|
);
|
|
5417
5599
|
}
|
|
5600
|
+
async function resolveTargetSlot(serviceName) {
|
|
5601
|
+
const liveEntries = await listProjects().catch(() => []);
|
|
5602
|
+
const target = routeSpanToProject(serviceName, liveEntries);
|
|
5603
|
+
let slot = slots.get(target) ?? slots.get(DEFAULT_PROJECT);
|
|
5604
|
+
if (!slot) return null;
|
|
5605
|
+
if (slot.status === "broken") {
|
|
5606
|
+
const entry = liveEntries.find((e) => e.name === slot.entry.name);
|
|
5607
|
+
if (entry) {
|
|
5608
|
+
slot = await tryRecoverSlot(entry);
|
|
5609
|
+
}
|
|
5610
|
+
if (slot.status !== "active") {
|
|
5611
|
+
warnDroppedSpan(slot.entry.name, slot.errorReason ?? "unknown");
|
|
5612
|
+
return null;
|
|
5613
|
+
}
|
|
5614
|
+
}
|
|
5615
|
+
return slot.status === "active" ? slot : null;
|
|
5616
|
+
}
|
|
5418
5617
|
try {
|
|
5419
5618
|
otlpApp = await buildOtelReceiver({
|
|
5619
|
+
authToken: auth.otelToken,
|
|
5620
|
+
trustProxy: auth.trustProxy,
|
|
5420
5621
|
onSpan: async (span) => {
|
|
5421
|
-
const
|
|
5422
|
-
|
|
5423
|
-
const slot = slots.get(target) ?? slots.get(DEFAULT_PROJECT);
|
|
5424
|
-
if (!slot || slot.status !== "active") return;
|
|
5622
|
+
const slot = await resolveTargetSlot(span.service);
|
|
5623
|
+
if (!slot) return;
|
|
5425
5624
|
await handleSpan(
|
|
5426
5625
|
{
|
|
5427
5626
|
graph: slot.graph,
|
|
@@ -5434,10 +5633,8 @@ async function startDaemon(opts = {}) {
|
|
|
5434
5633
|
);
|
|
5435
5634
|
},
|
|
5436
5635
|
onErrorSpanSync: async (span) => {
|
|
5437
|
-
const
|
|
5438
|
-
|
|
5439
|
-
const slot = slots.get(target) ?? slots.get(DEFAULT_PROJECT);
|
|
5440
|
-
if (!slot || slot.status !== "active") return;
|
|
5636
|
+
const slot = await resolveTargetSlot(span.service);
|
|
5637
|
+
if (!slot) return;
|
|
5441
5638
|
await makeErrorSpanWriter(slot.paths.errorsPath)(span);
|
|
5442
5639
|
}
|
|
5443
5640
|
});
|