@logscopeai/logscope 0.1.0-beta.2
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/README.md +341 -0
- package/dist/client/create-logscope-client.d.ts +23 -0
- package/dist/client/create-logscope-client.js +112 -0
- package/dist/client/create-logscope-client.js.map +1 -0
- package/dist/client/log-methods.d.ts +3 -0
- package/dist/client/log-methods.js +27 -0
- package/dist/client/log-methods.js.map +1 -0
- package/dist/config/config-guards.d.ts +31 -0
- package/dist/config/config-guards.js +128 -0
- package/dist/config/config-guards.js.map +1 -0
- package/dist/config/runtime-config.d.ts +17 -0
- package/dist/config/runtime-config.js +41 -0
- package/dist/config/runtime-config.js.map +1 -0
- package/dist/console/capture-console.d.ts +16 -0
- package/dist/console/capture-console.js +117 -0
- package/dist/console/capture-console.js.map +1 -0
- package/dist/constants.d.ts +7 -0
- package/dist/constants.js +17 -0
- package/dist/constants.js.map +1 -0
- package/dist/filter/level-filter.d.ts +3 -0
- package/dist/filter/level-filter.js +16 -0
- package/dist/filter/level-filter.js.map +1 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.js +26 -0
- package/dist/index.js.map +1 -0
- package/dist/logscope.d.ts +11 -0
- package/dist/logscope.js +61 -0
- package/dist/logscope.js.map +1 -0
- package/dist/normalization/normalize-log.d.ts +12 -0
- package/dist/normalization/normalize-log.js +140 -0
- package/dist/normalization/normalize-log.js.map +1 -0
- package/dist/pino/map-pino-level.d.ts +2 -0
- package/dist/pino/map-pino-level.js +40 -0
- package/dist/pino/map-pino-level.js.map +1 -0
- package/dist/pino/transport.d.ts +20 -0
- package/dist/pino/transport.js +185 -0
- package/dist/pino/transport.js.map +1 -0
- package/dist/pino.d.ts +4 -0
- package/dist/pino.js +11 -0
- package/dist/pino.js.map +1 -0
- package/dist/pipeline/batch-queue.d.ts +9 -0
- package/dist/pipeline/batch-queue.js +29 -0
- package/dist/pipeline/batch-queue.js.map +1 -0
- package/dist/pipeline/delivery-runner.d.ts +12 -0
- package/dist/pipeline/delivery-runner.js +63 -0
- package/dist/pipeline/delivery-runner.js.map +1 -0
- package/dist/pipeline/flush-scheduler.d.ts +14 -0
- package/dist/pipeline/flush-scheduler.js +39 -0
- package/dist/pipeline/flush-scheduler.js.map +1 -0
- package/dist/pipeline/pipeline-ingress.d.ts +19 -0
- package/dist/pipeline/pipeline-ingress.js +37 -0
- package/dist/pipeline/pipeline-ingress.js.map +1 -0
- package/dist/pipeline/pipeline.d.ts +21 -0
- package/dist/pipeline/pipeline.js +109 -0
- package/dist/pipeline/pipeline.js.map +1 -0
- package/dist/retry/backoff.d.ts +2 -0
- package/dist/retry/backoff.js +16 -0
- package/dist/retry/backoff.js.map +1 -0
- package/dist/retry/retry-policy.d.ts +7 -0
- package/dist/retry/retry-policy.js +26 -0
- package/dist/retry/retry-policy.js.map +1 -0
- package/dist/transport/send-ingestion-request.d.ts +4 -0
- package/dist/transport/send-ingestion-request.js +75 -0
- package/dist/transport/send-ingestion-request.js.map +1 -0
- package/dist/transport/transport-types.d.ts +39 -0
- package/dist/transport/transport-types.js +3 -0
- package/dist/transport/transport-types.js.map +1 -0
- package/dist/types.d.ts +69 -0
- package/dist/types.js +3 -0
- package/dist/types.js.map +1 -0
- package/package.json +62 -0
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createPipelineIngress = void 0;
|
|
4
|
+
const level_filter_1 = require("../filter/level-filter");
|
|
5
|
+
const normalize_log_1 = require("../normalization/normalize-log");
|
|
6
|
+
const runSafe = (callback) => {
|
|
7
|
+
try {
|
|
8
|
+
callback();
|
|
9
|
+
}
|
|
10
|
+
catch {
|
|
11
|
+
// Never throw into user code.
|
|
12
|
+
}
|
|
13
|
+
};
|
|
14
|
+
const createPipelineIngress = (input) => {
|
|
15
|
+
const allowsLevel = (0, level_filter_1.createLevelFilterEvaluator)(input.logFilter);
|
|
16
|
+
return {
|
|
17
|
+
dispatch(log) {
|
|
18
|
+
if (!allowsLevel(log.level)) {
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
runSafe(() => {
|
|
22
|
+
const normalizedLog = (0, normalize_log_1.normalizeLog)({
|
|
23
|
+
source: input.source,
|
|
24
|
+
level: log.level,
|
|
25
|
+
message: log.message,
|
|
26
|
+
metadata: log.metadata,
|
|
27
|
+
timestamp: log.timestamp,
|
|
28
|
+
}, {
|
|
29
|
+
now: input.now,
|
|
30
|
+
});
|
|
31
|
+
input.pipeline.enqueue(normalizedLog);
|
|
32
|
+
});
|
|
33
|
+
},
|
|
34
|
+
};
|
|
35
|
+
};
|
|
36
|
+
exports.createPipelineIngress = createPipelineIngress;
|
|
37
|
+
//# sourceMappingURL=pipeline-ingress.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pipeline-ingress.js","sourceRoot":"","sources":["../../src/pipeline/pipeline-ingress.ts"],"names":[],"mappings":";;;AAAA,yDAAoE;AACpE,kEAA8D;AAuB9D,MAAM,OAAO,GAAG,CAAC,QAAoB,EAAQ,EAAE;IAC7C,IAAI,CAAC;QACH,QAAQ,EAAE,CAAC;IACb,CAAC;IAAC,MAAM,CAAC;QACP,8BAA8B;IAChC,CAAC;AACH,CAAC,CAAC;AAEK,MAAM,qBAAqB,GAAG,CAAC,KAAiC,EAAmB,EAAE;IAC1F,MAAM,WAAW,GAAG,IAAA,yCAA0B,EAAC,KAAK,CAAC,SAAS,CAAC,CAAC;IAEhE,OAAO;QACL,QAAQ,CAAC,GAA4B;YACnC,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC;gBAC5B,OAAO;YACT,CAAC;YAED,OAAO,CAAC,GAAG,EAAE;gBACX,MAAM,aAAa,GAAG,IAAA,4BAAY,EAChC;oBACE,MAAM,EAAE,KAAK,CAAC,MAAM;oBACpB,KAAK,EAAE,GAAG,CAAC,KAAK;oBAChB,OAAO,EAAE,GAAG,CAAC,OAAO;oBACpB,QAAQ,EAAE,GAAG,CAAC,QAAQ;oBACtB,SAAS,EAAE,GAAG,CAAC,SAAS;iBACzB,EACD;oBACE,GAAG,EAAE,KAAK,CAAC,GAAG;iBACf,CACF,CAAC;gBAEF,KAAK,CAAC,QAAQ,CAAC,OAAO,CAAC,aAAa,CAAC,CAAC;YACxC,CAAC,CAAC,CAAC;QACL,CAAC;KACF,CAAC;AACJ,CAAC,CAAC;AA3BW,QAAA,qBAAqB,yBA2BhC"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { DEFAULT_FLUSH_INTERVAL_MS } from '../config/runtime-config';
|
|
2
|
+
import type { RetryPolicy } from '../retry/retry-policy';
|
|
3
|
+
import type { IngestionRequestResult, SendIngestionRequestInput } from '../transport/transport-types';
|
|
4
|
+
import type { IngestionLogEntry } from '../types';
|
|
5
|
+
export declare const MAX_BATCH_SIZE = 50;
|
|
6
|
+
export { DEFAULT_FLUSH_INTERVAL_MS };
|
|
7
|
+
export interface BatchingPipeline {
|
|
8
|
+
enqueue(log: IngestionLogEntry): void;
|
|
9
|
+
flushNow(): Promise<void>;
|
|
10
|
+
stop(): Promise<void>;
|
|
11
|
+
}
|
|
12
|
+
export interface CreateBatchingPipelineInput {
|
|
13
|
+
endpoint: string;
|
|
14
|
+
apiKey: string;
|
|
15
|
+
sendBatch: (input: SendIngestionRequestInput) => Promise<IngestionRequestResult>;
|
|
16
|
+
onBatchResult?: (result: IngestionRequestResult) => void;
|
|
17
|
+
maxBatchSize?: number;
|
|
18
|
+
flushIntervalMs?: number;
|
|
19
|
+
retryPolicy?: Partial<RetryPolicy>;
|
|
20
|
+
}
|
|
21
|
+
export declare const createBatchingPipeline: (input: CreateBatchingPipelineInput) => BatchingPipeline;
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createBatchingPipeline = exports.DEFAULT_FLUSH_INTERVAL_MS = exports.MAX_BATCH_SIZE = void 0;
|
|
4
|
+
const runtime_config_1 = require("../config/runtime-config");
|
|
5
|
+
Object.defineProperty(exports, "DEFAULT_FLUSH_INTERVAL_MS", { enumerable: true, get: function () { return runtime_config_1.DEFAULT_FLUSH_INTERVAL_MS; } });
|
|
6
|
+
const batch_queue_1 = require("./batch-queue");
|
|
7
|
+
const delivery_runner_1 = require("./delivery-runner");
|
|
8
|
+
const flush_scheduler_1 = require("./flush-scheduler");
|
|
9
|
+
exports.MAX_BATCH_SIZE = runtime_config_1.DEFAULT_MAX_BATCH_SIZE;
|
|
10
|
+
const runSafe = (callback) => {
|
|
11
|
+
try {
|
|
12
|
+
callback();
|
|
13
|
+
}
|
|
14
|
+
catch {
|
|
15
|
+
// Internal callbacks must not surface to user code.
|
|
16
|
+
}
|
|
17
|
+
};
|
|
18
|
+
const createBatchingPipeline = (input) => {
|
|
19
|
+
const runtimeConfig = (0, runtime_config_1.resolveRuntimeConfig)({
|
|
20
|
+
maxBatchSize: input.maxBatchSize,
|
|
21
|
+
flushIntervalMs: input.flushIntervalMs,
|
|
22
|
+
maxRetries: input.retryPolicy?.maxRetries,
|
|
23
|
+
retryBaseDelayMs: input.retryPolicy?.baseDelayMs,
|
|
24
|
+
retryMaxDelayMs: input.retryPolicy?.maxDelayMs,
|
|
25
|
+
});
|
|
26
|
+
const queue = (0, batch_queue_1.createBatchQueue)();
|
|
27
|
+
let activeFlushPromise = null;
|
|
28
|
+
let isStopped = false;
|
|
29
|
+
const emitBatchResult = (result) => {
|
|
30
|
+
if (input.onBatchResult === undefined) {
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
runSafe(() => input.onBatchResult?.(result));
|
|
34
|
+
};
|
|
35
|
+
const scheduler = (0, flush_scheduler_1.createFlushScheduler)({
|
|
36
|
+
intervalMs: runtimeConfig.flushIntervalMs,
|
|
37
|
+
onFlush: () => {
|
|
38
|
+
if (isStopped || queue.isEmpty()) {
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
void flushInternal();
|
|
42
|
+
},
|
|
43
|
+
});
|
|
44
|
+
const flushInternal = () => {
|
|
45
|
+
if (activeFlushPromise !== null) {
|
|
46
|
+
return activeFlushPromise;
|
|
47
|
+
}
|
|
48
|
+
activeFlushPromise = (async () => {
|
|
49
|
+
scheduler.cancel();
|
|
50
|
+
while (!queue.isEmpty()) {
|
|
51
|
+
const batch = queue.dequeueBatch(runtimeConfig.maxBatchSize);
|
|
52
|
+
if (batch.length === 0) {
|
|
53
|
+
break;
|
|
54
|
+
}
|
|
55
|
+
try {
|
|
56
|
+
const result = await (0, delivery_runner_1.runBatchDelivery)({
|
|
57
|
+
endpoint: input.endpoint,
|
|
58
|
+
apiKey: input.apiKey,
|
|
59
|
+
sendBatch: input.sendBatch,
|
|
60
|
+
logs: batch,
|
|
61
|
+
retryPolicy: runtimeConfig.retryPolicy,
|
|
62
|
+
});
|
|
63
|
+
emitBatchResult(result);
|
|
64
|
+
}
|
|
65
|
+
catch {
|
|
66
|
+
// Never throw into user code.
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
})().finally(() => {
|
|
70
|
+
activeFlushPromise = null;
|
|
71
|
+
if (isStopped || queue.isEmpty()) {
|
|
72
|
+
scheduler.cancel();
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
scheduler.schedule();
|
|
76
|
+
});
|
|
77
|
+
return activeFlushPromise;
|
|
78
|
+
};
|
|
79
|
+
return {
|
|
80
|
+
enqueue(log) {
|
|
81
|
+
if (isStopped) {
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
queue.enqueue(log);
|
|
85
|
+
if (queue.size() >= runtimeConfig.maxBatchSize) {
|
|
86
|
+
void flushInternal();
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
scheduler.schedule();
|
|
90
|
+
},
|
|
91
|
+
async flushNow() {
|
|
92
|
+
if (isStopped || queue.isEmpty()) {
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
await flushInternal();
|
|
96
|
+
},
|
|
97
|
+
async stop() {
|
|
98
|
+
if (isStopped) {
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
101
|
+
isStopped = true;
|
|
102
|
+
scheduler.cancel();
|
|
103
|
+
await flushInternal();
|
|
104
|
+
queue.clear();
|
|
105
|
+
},
|
|
106
|
+
};
|
|
107
|
+
};
|
|
108
|
+
exports.createBatchingPipeline = createBatchingPipeline;
|
|
109
|
+
//# sourceMappingURL=pipeline.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pipeline.js","sourceRoot":"","sources":["../../src/pipeline/pipeline.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.calculateRetryDelayMs = void 0;
|
|
4
|
+
const calculateRetryDelayMs = (attempt, policy) => {
|
|
5
|
+
if (attempt <= 0 || policy.baseDelayMs === 0 || policy.maxDelayMs === 0) {
|
|
6
|
+
return 0;
|
|
7
|
+
}
|
|
8
|
+
const growthFactor = 2 ** (attempt - 1);
|
|
9
|
+
const rawDelay = policy.baseDelayMs * growthFactor;
|
|
10
|
+
if (!Number.isFinite(rawDelay)) {
|
|
11
|
+
return policy.maxDelayMs;
|
|
12
|
+
}
|
|
13
|
+
return Math.min(policy.maxDelayMs, Math.trunc(rawDelay));
|
|
14
|
+
};
|
|
15
|
+
exports.calculateRetryDelayMs = calculateRetryDelayMs;
|
|
16
|
+
//# sourceMappingURL=backoff.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"backoff.js","sourceRoot":"","sources":["../../src/retry/backoff.ts"],"names":[],"mappings":";;;AAEO,MAAM,qBAAqB,GAAG,CAAC,OAAe,EAAE,MAAmB,EAAU,EAAE;IACpF,IAAI,OAAO,IAAI,CAAC,IAAI,MAAM,CAAC,WAAW,KAAK,CAAC,IAAI,MAAM,CAAC,UAAU,KAAK,CAAC,EAAE,CAAC;QACxE,OAAO,CAAC,CAAC;IACX,CAAC;IAED,MAAM,YAAY,GAAG,CAAC,IAAI,CAAC,OAAO,GAAG,CAAC,CAAC,CAAC;IACxC,MAAM,QAAQ,GAAG,MAAM,CAAC,WAAW,GAAG,YAAY,CAAC;IAEnD,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC;QAC/B,OAAO,MAAM,CAAC,UAAU,CAAC;IAC3B,CAAC;IAED,OAAO,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,UAAU,EAAE,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC;AAC3D,CAAC,CAAC;AAbW,QAAA,qBAAqB,yBAahC"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.resolveRetryPolicy = exports.DEFAULT_RETRY_POLICY = void 0;
|
|
4
|
+
exports.DEFAULT_RETRY_POLICY = {
|
|
5
|
+
maxRetries: 3,
|
|
6
|
+
baseDelayMs: 250,
|
|
7
|
+
maxDelayMs: 2_000,
|
|
8
|
+
};
|
|
9
|
+
const normalizeNonNegativeInteger = (value, fallback) => {
|
|
10
|
+
if (value === undefined || !Number.isFinite(value) || value < 0) {
|
|
11
|
+
return fallback;
|
|
12
|
+
}
|
|
13
|
+
return Math.trunc(value);
|
|
14
|
+
};
|
|
15
|
+
const resolveRetryPolicy = (policy) => {
|
|
16
|
+
const maxRetries = normalizeNonNegativeInteger(policy?.maxRetries, exports.DEFAULT_RETRY_POLICY.maxRetries);
|
|
17
|
+
const baseDelayMs = normalizeNonNegativeInteger(policy?.baseDelayMs, exports.DEFAULT_RETRY_POLICY.baseDelayMs);
|
|
18
|
+
const maxDelayMs = normalizeNonNegativeInteger(policy?.maxDelayMs, exports.DEFAULT_RETRY_POLICY.maxDelayMs);
|
|
19
|
+
return {
|
|
20
|
+
maxRetries,
|
|
21
|
+
baseDelayMs,
|
|
22
|
+
maxDelayMs: Math.max(baseDelayMs, maxDelayMs),
|
|
23
|
+
};
|
|
24
|
+
};
|
|
25
|
+
exports.resolveRetryPolicy = resolveRetryPolicy;
|
|
26
|
+
//# sourceMappingURL=retry-policy.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"retry-policy.js","sourceRoot":"","sources":["../../src/retry/retry-policy.ts"],"names":[],"mappings":";;;AAMa,QAAA,oBAAoB,GAAgB;IAC/C,UAAU,EAAE,CAAC;IACb,WAAW,EAAE,GAAG;IAChB,UAAU,EAAE,KAAK;CAClB,CAAC;AAEF,MAAM,2BAA2B,GAAG,CAAC,KAAyB,EAAE,QAAgB,EAAU,EAAE;IAC1F,IAAI,KAAK,KAAK,SAAS,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,KAAK,GAAG,CAAC,EAAE,CAAC;QAChE,OAAO,QAAQ,CAAC;IAClB,CAAC;IAED,OAAO,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;AAC3B,CAAC,CAAC;AAEK,MAAM,kBAAkB,GAAG,CAAC,MAA6B,EAAe,EAAE;IAC/E,MAAM,UAAU,GAAG,2BAA2B,CAC5C,MAAM,EAAE,UAAU,EAClB,4BAAoB,CAAC,UAAU,CAChC,CAAC;IACF,MAAM,WAAW,GAAG,2BAA2B,CAC7C,MAAM,EAAE,WAAW,EACnB,4BAAoB,CAAC,WAAW,CACjC,CAAC;IACF,MAAM,UAAU,GAAG,2BAA2B,CAC5C,MAAM,EAAE,UAAU,EAClB,4BAAoB,CAAC,UAAU,CAChC,CAAC;IAEF,OAAO;QACL,UAAU;QACV,WAAW;QACX,UAAU,EAAE,IAAI,CAAC,GAAG,CAAC,WAAW,EAAE,UAAU,CAAC;KAC9C,CAAC;AACJ,CAAC,CAAC;AAnBW,QAAA,kBAAkB,sBAmB7B"}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.sendIngestionRequest = void 0;
|
|
4
|
+
const INGESTION_PATH = '/api/logs/ingest';
|
|
5
|
+
// Explicit status classification for ingestion delivery behavior.
|
|
6
|
+
const classifyIngestionStatus = (status) => {
|
|
7
|
+
switch (status) {
|
|
8
|
+
case 202:
|
|
9
|
+
return 'success';
|
|
10
|
+
case 400:
|
|
11
|
+
case 413:
|
|
12
|
+
return 'drop';
|
|
13
|
+
case 401:
|
|
14
|
+
return 'unauthorized';
|
|
15
|
+
case 429:
|
|
16
|
+
case 500:
|
|
17
|
+
return 'retry';
|
|
18
|
+
default:
|
|
19
|
+
return status >= 500 ? 'retry' : 'drop';
|
|
20
|
+
}
|
|
21
|
+
};
|
|
22
|
+
const buildIngestionUrl = (endpoint) => {
|
|
23
|
+
return new URL(INGESTION_PATH, endpoint).toString();
|
|
24
|
+
};
|
|
25
|
+
const buildRequestInit = (input) => {
|
|
26
|
+
return {
|
|
27
|
+
method: 'POST',
|
|
28
|
+
headers: {
|
|
29
|
+
'x-api-key': input.apiKey,
|
|
30
|
+
'Content-Type': 'application/json',
|
|
31
|
+
},
|
|
32
|
+
body: JSON.stringify({
|
|
33
|
+
logs: input.logs,
|
|
34
|
+
}),
|
|
35
|
+
};
|
|
36
|
+
};
|
|
37
|
+
const sendIngestionRequest = async (input, dependencies = { fetch: globalThis.fetch }) => {
|
|
38
|
+
let requestUrl;
|
|
39
|
+
try {
|
|
40
|
+
requestUrl = buildIngestionUrl(input.endpoint);
|
|
41
|
+
}
|
|
42
|
+
catch {
|
|
43
|
+
return {
|
|
44
|
+
action: 'drop',
|
|
45
|
+
shouldWarnUnauthorized: false,
|
|
46
|
+
errorKind: 'invalid_endpoint',
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
try {
|
|
50
|
+
console.log(`[logscope] Sending logs batch to ${requestUrl}`);
|
|
51
|
+
const response = await dependencies.fetch(requestUrl, buildRequestInit(input));
|
|
52
|
+
const action = classifyIngestionStatus(response.status);
|
|
53
|
+
if (action === 'unauthorized') {
|
|
54
|
+
return {
|
|
55
|
+
action,
|
|
56
|
+
status: response.status,
|
|
57
|
+
shouldWarnUnauthorized: true,
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
return {
|
|
61
|
+
action,
|
|
62
|
+
status: response.status,
|
|
63
|
+
shouldWarnUnauthorized: false,
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
catch {
|
|
67
|
+
return {
|
|
68
|
+
action: 'retry',
|
|
69
|
+
shouldWarnUnauthorized: false,
|
|
70
|
+
errorKind: 'network_error',
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
};
|
|
74
|
+
exports.sendIngestionRequest = sendIngestionRequest;
|
|
75
|
+
//# sourceMappingURL=send-ingestion-request.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"send-ingestion-request.js","sourceRoot":"","sources":["../../src/transport/send-ingestion-request.ts"],"names":[],"mappings":";;;AAQA,MAAM,cAAc,GAAG,kBAAkB,CAAC;AAE1C,kEAAkE;AAClE,MAAM,uBAAuB,GAAG,CAAC,MAAc,EAA0B,EAAE;IACzE,QAAQ,MAAM,EAAE,CAAC;QACf,KAAK,GAAG;YACN,OAAO,SAAS,CAAC;QACnB,KAAK,GAAG,CAAC;QACT,KAAK,GAAG;YACN,OAAO,MAAM,CAAC;QAChB,KAAK,GAAG;YACN,OAAO,cAAc,CAAC;QACxB,KAAK,GAAG,CAAC;QACT,KAAK,GAAG;YACN,OAAO,OAAO,CAAC;QACjB;YACE,OAAO,MAAM,IAAI,GAAG,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC;IAC5C,CAAC;AACH,CAAC,CAAC;AAEF,MAAM,iBAAiB,GAAG,CAAC,QAAgB,EAAU,EAAE;IACrD,OAAO,IAAI,GAAG,CAAC,cAAc,EAAE,QAAQ,CAAC,CAAC,QAAQ,EAAE,CAAC;AACtD,CAAC,CAAC;AAEF,MAAM,gBAAgB,GAAG,CAAC,KAAgC,EAAoB,EAAE;IAC9E,OAAO;QACL,MAAM,EAAE,MAAM;QACd,OAAO,EAAE;YACP,WAAW,EAAE,KAAK,CAAC,MAAM;YACzB,cAAc,EAAE,kBAAkB;SACnC;QACD,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC;YACnB,IAAI,EAAE,KAAK,CAAC,IAAI;SACjB,CAAC;KACH,CAAC;AACJ,CAAC,CAAC;AAEK,MAAM,oBAAoB,GAAG,KAAK,EACvC,KAAgC,EAChC,eAAqC,EAAE,KAAK,EAAE,UAAU,CAAC,KAA6B,EAAE,EACvD,EAAE;IACnC,IAAI,UAAkB,CAAC;IAEvB,IAAI,CAAC;QACH,UAAU,GAAG,iBAAiB,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;IACjD,CAAC;IAAC,MAAM,CAAC;QACP,OAAO;YACL,MAAM,EAAE,MAAM;YACd,sBAAsB,EAAE,KAAK;YAC7B,SAAS,EAAE,kBAAkB;SAC9B,CAAC;IACJ,CAAC;IAED,IAAI,CAAC;QACH,OAAO,CAAC,GAAG,CAAC,oCAAoC,UAAU,EAAE,CAAC,CAAC;QAC9D,MAAM,QAAQ,GAAG,MAAM,YAAY,CAAC,KAAK,CAAC,UAAU,EAAE,gBAAgB,CAAC,KAAK,CAAC,CAAC,CAAC;QAC/E,MAAM,MAAM,GAAG,uBAAuB,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;QAExD,IAAI,MAAM,KAAK,cAAc,EAAE,CAAC;YAC9B,OAAO;gBACL,MAAM;gBACN,MAAM,EAAE,QAAQ,CAAC,MAAM;gBACvB,sBAAsB,EAAE,IAAI;aAC7B,CAAC;QACJ,CAAC;QAED,OAAO;YACL,MAAM;YACN,MAAM,EAAE,QAAQ,CAAC,MAAM;YACvB,sBAAsB,EAAE,KAAK;SAC9B,CAAC;IACJ,CAAC;IAAC,MAAM,CAAC;QACP,OAAO;YACL,MAAM,EAAE,OAAO;YACf,sBAAsB,EAAE,KAAK;YAC7B,SAAS,EAAE,eAAe;SAC3B,CAAC;IACJ,CAAC;AACH,CAAC,CAAC;AAzCW,QAAA,oBAAoB,wBAyC/B"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import type { IngestionLogEntry } from '../types';
|
|
2
|
+
export type IngestionRequestAction = 'success' | 'drop' | 'retry' | 'unauthorized';
|
|
3
|
+
export type IngestionDropErrorKind = 'invalid_endpoint' | 'max_retries_exceeded';
|
|
4
|
+
export type IngestionRetryErrorKind = 'network_error';
|
|
5
|
+
export type IngestionRequestResult = {
|
|
6
|
+
action: 'success';
|
|
7
|
+
status?: number;
|
|
8
|
+
shouldWarnUnauthorized: false;
|
|
9
|
+
errorKind?: never;
|
|
10
|
+
} | {
|
|
11
|
+
action: 'drop';
|
|
12
|
+
status?: number;
|
|
13
|
+
shouldWarnUnauthorized: false;
|
|
14
|
+
errorKind?: IngestionDropErrorKind;
|
|
15
|
+
} | {
|
|
16
|
+
action: 'retry';
|
|
17
|
+
status?: number;
|
|
18
|
+
shouldWarnUnauthorized: false;
|
|
19
|
+
errorKind?: IngestionRetryErrorKind;
|
|
20
|
+
} | {
|
|
21
|
+
action: 'unauthorized';
|
|
22
|
+
status?: number;
|
|
23
|
+
shouldWarnUnauthorized: true;
|
|
24
|
+
errorKind?: never;
|
|
25
|
+
};
|
|
26
|
+
export interface SendIngestionRequestInput {
|
|
27
|
+
endpoint: string;
|
|
28
|
+
apiKey: string;
|
|
29
|
+
logs: IngestionLogEntry[];
|
|
30
|
+
}
|
|
31
|
+
export interface FetchRequestInit {
|
|
32
|
+
method: 'POST';
|
|
33
|
+
headers: Record<string, string>;
|
|
34
|
+
body: string;
|
|
35
|
+
}
|
|
36
|
+
export interface FetchResponseLike {
|
|
37
|
+
status: number;
|
|
38
|
+
}
|
|
39
|
+
export type FetchLike = (url: string, init: FetchRequestInit) => Promise<FetchResponseLike>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"transport-types.js","sourceRoot":"","sources":["../../src/transport/transport-types.ts"],"names":[],"mappings":""}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
export type LogLevel = 'trace' | 'debug' | 'info' | 'warn' | 'error' | 'fatal';
|
|
2
|
+
export interface LogFilterConfig {
|
|
3
|
+
levels?: LogLevel[];
|
|
4
|
+
}
|
|
5
|
+
export interface LogscopeRuntimeConfig {
|
|
6
|
+
maxBatchSize?: number;
|
|
7
|
+
flushIntervalMs?: number;
|
|
8
|
+
maxRetries?: number;
|
|
9
|
+
retryBaseDelayMs?: number;
|
|
10
|
+
retryMaxDelayMs?: number;
|
|
11
|
+
}
|
|
12
|
+
interface LogscopeConfigBase {
|
|
13
|
+
apiKey: string;
|
|
14
|
+
captureConsole?: boolean;
|
|
15
|
+
context?: {
|
|
16
|
+
/**
|
|
17
|
+
* @deprecated Source input is optional and falls back safely when omitted.
|
|
18
|
+
*/
|
|
19
|
+
source?: string;
|
|
20
|
+
};
|
|
21
|
+
logFilter?: LogFilterConfig;
|
|
22
|
+
runtime?: LogscopeRuntimeConfig;
|
|
23
|
+
}
|
|
24
|
+
export interface LogscopeInitConfig {
|
|
25
|
+
apiKey: string;
|
|
26
|
+
ingestionBaseUrl?: string;
|
|
27
|
+
/**
|
|
28
|
+
* @deprecated Use ingestionBaseUrl instead.
|
|
29
|
+
*/
|
|
30
|
+
endpoint?: string;
|
|
31
|
+
captureConsole?: boolean;
|
|
32
|
+
context?: {
|
|
33
|
+
/**
|
|
34
|
+
* @deprecated Source input is optional and falls back safely when omitted.
|
|
35
|
+
*/
|
|
36
|
+
source?: string;
|
|
37
|
+
};
|
|
38
|
+
logFilter?: LogFilterConfig;
|
|
39
|
+
runtime?: LogscopeRuntimeConfig;
|
|
40
|
+
}
|
|
41
|
+
interface LogscopeIngestionTarget {
|
|
42
|
+
ingestionBaseUrl?: string;
|
|
43
|
+
/**
|
|
44
|
+
* @deprecated Use ingestionBaseUrl instead.
|
|
45
|
+
*/
|
|
46
|
+
endpoint?: string;
|
|
47
|
+
}
|
|
48
|
+
export type LogscopeConfig = LogscopeConfigBase & LogscopeIngestionTarget;
|
|
49
|
+
export interface LogscopeClient {
|
|
50
|
+
trace(message: string, metadata?: unknown): void;
|
|
51
|
+
debug(message: string, metadata?: unknown): void;
|
|
52
|
+
info(message: string, metadata?: unknown): void;
|
|
53
|
+
warn(message: string, metadata?: unknown): void;
|
|
54
|
+
error(message: string, metadata?: unknown): void;
|
|
55
|
+
fatal(message: string, metadata?: unknown): void;
|
|
56
|
+
}
|
|
57
|
+
export type JsonSafePrimitive = string | number | boolean | null;
|
|
58
|
+
export type JsonSafeValue = JsonSafePrimitive | JsonSafeObject | JsonSafeValue[];
|
|
59
|
+
export interface JsonSafeObject {
|
|
60
|
+
[key: string]: JsonSafeValue;
|
|
61
|
+
}
|
|
62
|
+
export interface IngestionLogEntry {
|
|
63
|
+
source: string;
|
|
64
|
+
level: LogLevel;
|
|
65
|
+
timestamp: string;
|
|
66
|
+
message: string;
|
|
67
|
+
metadata?: Record<string, unknown>;
|
|
68
|
+
}
|
|
69
|
+
export {};
|
package/dist/types.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
|
package/package.json
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@logscopeai/logscope",
|
|
3
|
+
"version": "0.1.0-beta.2",
|
|
4
|
+
"description": "`logscope` is the official Node.js client SDK for Logscope.",
|
|
5
|
+
"main": "./dist/index.js",
|
|
6
|
+
"types": "./dist/index.d.ts",
|
|
7
|
+
"exports": {
|
|
8
|
+
".": {
|
|
9
|
+
"types": "./dist/index.d.ts",
|
|
10
|
+
"default": "./dist/index.js"
|
|
11
|
+
},
|
|
12
|
+
"./pino": {
|
|
13
|
+
"types": "./dist/pino.d.ts",
|
|
14
|
+
"default": "./dist/pino.js"
|
|
15
|
+
},
|
|
16
|
+
"./package.json": "./package.json"
|
|
17
|
+
},
|
|
18
|
+
"files": [
|
|
19
|
+
"dist",
|
|
20
|
+
"README.md",
|
|
21
|
+
"LICENSE"
|
|
22
|
+
],
|
|
23
|
+
"scripts": {
|
|
24
|
+
"build": "tsc -p tsconfig.json",
|
|
25
|
+
"prepublishOnly": "npm run build",
|
|
26
|
+
"test": "vitest run --coverage",
|
|
27
|
+
"test:coverage": "vitest run --coverage",
|
|
28
|
+
"test:watch": "vitest",
|
|
29
|
+
"format": "prettier --config .prettierrc --write .",
|
|
30
|
+
"format:check": "prettier --config .prettierrc --check ."
|
|
31
|
+
},
|
|
32
|
+
"repository": {
|
|
33
|
+
"type": "git",
|
|
34
|
+
"url": "git+https://github.com/logscopeai/logscope.git"
|
|
35
|
+
},
|
|
36
|
+
"keywords": [
|
|
37
|
+
"logscope",
|
|
38
|
+
"logging",
|
|
39
|
+
"sdk",
|
|
40
|
+
"nodejs"
|
|
41
|
+
],
|
|
42
|
+
"author": "",
|
|
43
|
+
"license": "MIT",
|
|
44
|
+
"bugs": {
|
|
45
|
+
"url": "https://github.com/logscopeai/logscope/issues"
|
|
46
|
+
},
|
|
47
|
+
"homepage": "https://github.com/logscopeai/logscope#readme",
|
|
48
|
+
"devDependencies": {
|
|
49
|
+
"@types/node": "^22.10.2",
|
|
50
|
+
"@vitest/coverage-v8": "^2.1.8",
|
|
51
|
+
"lint-staged": "^15.4.3",
|
|
52
|
+
"prettier": "^3.4.2",
|
|
53
|
+
"typescript": "^5.7.2",
|
|
54
|
+
"vitest": "^2.1.8"
|
|
55
|
+
},
|
|
56
|
+
"lint-staged": {
|
|
57
|
+
"*.{ts,js,tsx,jsx,html,css,scss,json,md}": "npx prettier --config .prettierrc --write"
|
|
58
|
+
},
|
|
59
|
+
"engines": {
|
|
60
|
+
"node": ">=20"
|
|
61
|
+
}
|
|
62
|
+
}
|