logixia 2.0.4 → 2.0.7
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/README.md +172 -2614
- package/dist/{async-context-B05ArHgM.mjs → async-context-COuvmwsS.mjs} +4 -6
- package/dist/async-context-COuvmwsS.mjs.map +1 -0
- package/dist/{async-context-DTQgi8f7.js → async-context-Dv0bmPC-.js} +4 -6
- package/dist/async-context-Dv0bmPC-.js.map +1 -0
- package/dist/{azure-monitor.transport-DV03Z5P4.d.ts → azure-monitor.transport-Bvf7Xegt.d.ts} +2 -2
- package/dist/{azure-monitor.transport-DV03Z5P4.d.ts.map → azure-monitor.transport-Bvf7Xegt.d.ts.map} +1 -1
- package/dist/{azure-monitor.transport-C7kYyZUW.d.mts → azure-monitor.transport-CbSHOnNX.d.mts} +2 -2
- package/dist/{azure-monitor.transport-C7kYyZUW.d.mts.map → azure-monitor.transport-CbSHOnNX.d.mts.map} +1 -1
- package/dist/{azure-monitor.transport-BPbgjATu.mjs → azure-monitor.transport-Coz5Gesu.mjs} +5 -5
- package/dist/azure-monitor.transport-Coz5Gesu.mjs.map +1 -0
- package/dist/{azure-monitor.transport-CwbOLZHB.js → azure-monitor.transport-D6ryi8rA.js} +5 -5
- package/dist/azure-monitor.transport-D6ryi8rA.js.map +1 -0
- package/dist/azure.d.mts +1 -1
- package/dist/azure.d.ts +1 -1
- package/dist/azure.js +1 -1
- package/dist/azure.mjs +1 -1
- package/dist/{batch-buffer-DT4gdXmf.js → batch-buffer-CFzKnuNZ.js} +3 -3
- package/dist/{batch-buffer-DT4gdXmf.js.map → batch-buffer-CFzKnuNZ.js.map} +1 -1
- package/dist/{batch-buffer-0fgLmIPn.mjs → batch-buffer-CQUWDMYq.mjs} +3 -3
- package/dist/{batch-buffer-0fgLmIPn.mjs.map → batch-buffer-CQUWDMYq.mjs.map} +1 -1
- package/dist/browser.d.mts +5 -5
- package/dist/browser.d.mts.map +1 -1
- package/dist/browser.d.ts +5 -5
- package/dist/browser.d.ts.map +1 -1
- package/dist/browser.js +72 -13
- package/dist/browser.js.map +1 -1
- package/dist/browser.mjs +72 -13
- package/dist/browser.mjs.map +1 -1
- package/dist/{builder-D70z6kjj.mjs → builder-C_TgxEOW.mjs} +106 -153
- package/dist/builder-C_TgxEOW.mjs.map +1 -0
- package/dist/{builder-M7NoaugM.js → builder-CzmM_4Ub.js} +110 -180
- package/dist/builder-CzmM_4Ub.js.map +1 -0
- package/dist/cli/index.js +157 -66
- package/dist/cloudwatch.d.mts +1 -1
- package/dist/cloudwatch.d.ts +1 -1
- package/dist/cloudwatch.js +1 -1
- package/dist/cloudwatch.mjs +1 -1
- package/dist/{cloudwatch.transport-Bf7L4I59.d.ts → cloudwatch.transport-CQyT6U91.d.ts} +2 -2
- package/dist/{cloudwatch.transport-Bf7L4I59.d.ts.map → cloudwatch.transport-CQyT6U91.d.ts.map} +1 -1
- package/dist/{cloudwatch.transport-Rj4yTpRn.d.mts → cloudwatch.transport-CjVrI6S4.d.mts} +2 -2
- package/dist/{cloudwatch.transport-Rj4yTpRn.d.mts.map → cloudwatch.transport-CjVrI6S4.d.mts.map} +1 -1
- package/dist/{cloudwatch.transport-BTvYfLs9.mjs → cloudwatch.transport-Cr1aeTGj.mjs} +6 -6
- package/dist/cloudwatch.transport-Cr1aeTGj.mjs.map +1 -0
- package/dist/{cloudwatch.transport-B2wKQFF7.js → cloudwatch.transport-D4G5xYfG.js} +6 -6
- package/dist/cloudwatch.transport-D4G5xYfG.js.map +1 -0
- package/dist/correlation.d.mts +10 -55
- package/dist/correlation.d.mts.map +1 -1
- package/dist/correlation.d.ts +10 -55
- package/dist/correlation.d.ts.map +1 -1
- package/dist/correlation.js +15 -13
- package/dist/correlation.js.map +1 -1
- package/dist/correlation.mjs +15 -13
- package/dist/correlation.mjs.map +1 -1
- package/dist/{entry-fields-RLd1jCoR.js → entry-fields-CVwoQplO.js} +8 -3
- package/dist/entry-fields-CVwoQplO.js.map +1 -0
- package/dist/{entry-fields-CGuvT2R0.mjs → entry-fields-DNTKQxoU.mjs} +8 -3
- package/dist/entry-fields-DNTKQxoU.mjs.map +1 -0
- package/dist/gcp.d.mts +1 -1
- package/dist/gcp.d.ts +1 -1
- package/dist/gcp.js +1 -1
- package/dist/gcp.mjs +1 -1
- package/dist/{gcp.transport-CFQfdAOK.d.ts → gcp.transport-BCIvdFV-.d.ts} +4 -4
- package/dist/{gcp.transport-CFQfdAOK.d.ts.map → gcp.transport-BCIvdFV-.d.ts.map} +1 -1
- package/dist/{gcp.transport-KZe9hCAR.js → gcp.transport-CVuRpchl.js} +20 -16
- package/dist/gcp.transport-CVuRpchl.js.map +1 -0
- package/dist/{gcp.transport-C5D72b1g.d.mts → gcp.transport-D9SdLPwP.d.mts} +4 -4
- package/dist/{gcp.transport-C5D72b1g.d.mts.map → gcp.transport-D9SdLPwP.d.mts.map} +1 -1
- package/dist/{gcp.transport-CGKopAhQ.mjs → gcp.transport-LLK2bw2-.mjs} +20 -16
- package/dist/gcp.transport-LLK2bw2-.mjs.map +1 -0
- package/dist/http-shapes-BnBkJcid.d.mts +32 -0
- package/dist/http-shapes-BnBkJcid.d.mts.map +1 -0
- package/dist/http-shapes-BnBkJcid.d.ts +32 -0
- package/dist/http-shapes-BnBkJcid.d.ts.map +1 -0
- package/dist/{index-xqaJtAZn.d.mts → index-BAkPHp5D.d.mts} +150 -8
- package/dist/index-BAkPHp5D.d.mts.map +1 -0
- package/dist/{index-DwozbmB4.d.ts → index-e7LowmAu.d.ts} +150 -8
- package/dist/index-e7LowmAu.d.ts.map +1 -0
- package/dist/index.d.mts +21 -65
- package/dist/index.d.mts.map +1 -1
- package/dist/index.d.ts +21 -65
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +26 -26
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +21 -21
- package/dist/index.mjs.map +1 -1
- package/dist/{internal-log-uCSd1PMc.mjs → internal-log-Cy5nF1ZL.mjs} +2 -81
- package/dist/internal-log-Cy5nF1ZL.mjs.map +1 -0
- package/dist/{internal-log-b0Vp4qrB.js → internal-log-DwqTjhpb.js} +1 -104
- package/dist/internal-log-DwqTjhpb.js.map +1 -0
- package/dist/{logitron-logger-D2B75Oc7.d.ts → logitron-logger-Qh3y9-WH.d.ts} +13 -100
- package/dist/logitron-logger-Qh3y9-WH.d.ts.map +1 -0
- package/dist/{logitron-logger-oEd6wNhf.d.mts → logitron-logger-sYuk8fOb.d.mts} +13 -100
- package/dist/logitron-logger-sYuk8fOb.d.mts.map +1 -0
- package/dist/middleware.d.mts +4 -17
- package/dist/middleware.d.mts.map +1 -1
- package/dist/middleware.d.ts +4 -17
- package/dist/middleware.d.ts.map +1 -1
- package/dist/middleware.js +9 -39
- package/dist/middleware.js.map +1 -1
- package/dist/middleware.mjs +7 -37
- package/dist/middleware.mjs.map +1 -1
- package/dist/nest.d.mts +24 -8
- package/dist/nest.d.mts.map +1 -1
- package/dist/nest.d.ts +24 -8
- package/dist/nest.d.ts.map +1 -1
- package/dist/nest.js +140 -27
- package/dist/nest.js.map +1 -1
- package/dist/nest.mjs +140 -27
- package/dist/nest.mjs.map +1 -1
- package/dist/{transport.manager-DkcEOlqV.js → otel-ChnVYRLA.js} +214 -23
- package/dist/otel-ChnVYRLA.js.map +1 -0
- package/dist/{transport.manager-eZ_EeC00.mjs → otel-DOuwGPCd.mjs} +173 -24
- package/dist/otel-DOuwGPCd.mjs.map +1 -0
- package/dist/{request-trace-C_fvIDv4.mjs → request-trace-BgNykH9M.mjs} +1 -5
- package/dist/{request-trace-C_fvIDv4.mjs.map → request-trace-BgNykH9M.mjs.map} +1 -1
- package/dist/{request-trace-wTJdKp6-.js → request-trace-ByujsUZk.js} +1 -5
- package/dist/{request-trace-wTJdKp6-.js.map → request-trace-ByujsUZk.js.map} +1 -1
- package/dist/{safe-stringify-BMRl3EX3.mjs → safe-stringify--7gbe95n.mjs} +37 -12
- package/dist/safe-stringify--7gbe95n.mjs.map +1 -0
- package/dist/{safe-stringify-DLz1Kz3o.js → safe-stringify-CN7icp8S.js} +37 -12
- package/dist/safe-stringify-CN7icp8S.js.map +1 -0
- package/dist/{search-DUfWuzFP.js → search-CRjhHxe9.js} +269 -25
- package/dist/search-CRjhHxe9.js.map +1 -0
- package/dist/{search-CazwyX5Z.d.ts → search-D-8HJADE.d.mts} +5 -2
- package/dist/search-D-8HJADE.d.mts.map +1 -0
- package/dist/{search-CWMVYC-R.mjs → search-DAXKE-P9.mjs} +269 -25
- package/dist/search-DAXKE-P9.mjs.map +1 -0
- package/dist/{search-BH33XhuU.d.mts → search-DPwTKPve.d.ts} +5 -2
- package/dist/search-DPwTKPve.d.ts.map +1 -0
- package/dist/search.d.mts +1 -1
- package/dist/search.d.ts +1 -1
- package/dist/search.js +1 -1
- package/dist/search.mjs +1 -1
- package/dist/{secret-config-CBZBs0p1.js → secret-config-BvFl2dC8.js} +7 -7
- package/dist/secret-config-BvFl2dC8.js.map +1 -0
- package/dist/{secret-config-BegMLkYl.mjs → secret-config-ByGq7kJd.mjs} +5 -5
- package/dist/secret-config-ByGq7kJd.mjs.map +1 -0
- package/dist/sensitive-names-CHMowujD.js +276 -0
- package/dist/sensitive-names-CHMowujD.js.map +1 -0
- package/dist/sensitive-names-o__1PUUR.mjs +217 -0
- package/dist/sensitive-names-o__1PUUR.mjs.map +1 -0
- package/dist/{slack.transport-DxHOXlLu.d.mts → slack.transport-BDyENuR0.d.mts} +2 -2
- package/dist/{slack.transport-DxHOXlLu.d.mts.map → slack.transport-BDyENuR0.d.mts.map} +1 -1
- package/dist/{slack.transport-DrirgDNy.d.ts → slack.transport-C6E0l4kw.d.ts} +2 -2
- package/dist/{slack.transport-DrirgDNy.d.ts.map → slack.transport-C6E0l4kw.d.ts.map} +1 -1
- package/dist/{slack.transport-Ce96JBDk.mjs → slack.transport-CSj1j0_X.mjs} +66 -15
- package/dist/slack.transport-CSj1j0_X.mjs.map +1 -0
- package/dist/{slack.transport-Dlx3xvb7.js → slack.transport-zLQ9MGxS.js} +67 -16
- package/dist/slack.transport-zLQ9MGxS.js.map +1 -0
- package/dist/testing.d.mts +11 -4
- package/dist/testing.d.mts.map +1 -1
- package/dist/testing.d.ts +11 -4
- package/dist/testing.d.ts.map +1 -1
- package/dist/testing.js +38 -3
- package/dist/testing.js.map +1 -1
- package/dist/testing.mjs +38 -3
- package/dist/testing.mjs.map +1 -1
- package/dist/{transport.types-BJVL1QQl.d.ts → transport.types-CzJq4IrF.d.mts} +14 -3
- package/dist/transport.types-CzJq4IrF.d.mts.map +1 -0
- package/dist/{transport.types-BJVL1QQl.d.mts → transport.types-CzJq4IrF.d.ts} +14 -3
- package/dist/transport.types-CzJq4IrF.d.ts.map +1 -0
- package/dist/transports.d.mts +25 -13
- package/dist/transports.d.mts.map +1 -1
- package/dist/transports.d.ts +25 -13
- package/dist/transports.d.ts.map +1 -1
- package/dist/transports.js +15 -15
- package/dist/transports.mjs +6 -6
- package/dist/worker-entry.js +130 -25
- package/dist/worker.d.mts +1 -1
- package/dist/worker.d.ts +1 -1
- package/dist/worker.js +1 -1
- package/dist/worker.mjs +1 -1
- package/dist/{worker.transport-BuPwBi3d.d.ts → worker.transport-B9mCQSM1.d.ts} +7 -2
- package/dist/worker.transport-B9mCQSM1.d.ts.map +1 -0
- package/dist/{worker.transport-hJay1wxA.d.mts → worker.transport-Bl8lFRck.d.mts} +7 -2
- package/dist/worker.transport-Bl8lFRck.d.mts.map +1 -0
- package/dist/{worker.transport-DLVA4y2e.mjs → worker.transport-D78xhNhB.mjs} +13 -10
- package/dist/worker.transport-D78xhNhB.mjs.map +1 -0
- package/dist/{worker.transport-C6GNl_r2.js → worker.transport-DQDv1nAJ.js} +13 -10
- package/dist/worker.transport-DQDv1nAJ.js.map +1 -0
- package/package.json +33 -65
- package/dist/async-context-B05ArHgM.mjs.map +0 -1
- package/dist/async-context-DTQgi8f7.js.map +0 -1
- package/dist/azure-monitor.transport-BPbgjATu.mjs.map +0 -1
- package/dist/azure-monitor.transport-CwbOLZHB.js.map +0 -1
- package/dist/builder-D70z6kjj.mjs.map +0 -1
- package/dist/builder-M7NoaugM.js.map +0 -1
- package/dist/cloudwatch.transport-B2wKQFF7.js.map +0 -1
- package/dist/cloudwatch.transport-BTvYfLs9.mjs.map +0 -1
- package/dist/entry-fields-CGuvT2R0.mjs.map +0 -1
- package/dist/entry-fields-RLd1jCoR.js.map +0 -1
- package/dist/gcp.transport-CGKopAhQ.mjs.map +0 -1
- package/dist/gcp.transport-KZe9hCAR.js.map +0 -1
- package/dist/index-DwozbmB4.d.ts.map +0 -1
- package/dist/index-xqaJtAZn.d.mts.map +0 -1
- package/dist/internal-log-b0Vp4qrB.js.map +0 -1
- package/dist/internal-log-uCSd1PMc.mjs.map +0 -1
- package/dist/logitron-logger-D2B75Oc7.d.ts.map +0 -1
- package/dist/logitron-logger-oEd6wNhf.d.mts.map +0 -1
- package/dist/safe-stringify-BMRl3EX3.mjs.map +0 -1
- package/dist/safe-stringify-DLz1Kz3o.js.map +0 -1
- package/dist/search-BH33XhuU.d.mts.map +0 -1
- package/dist/search-CWMVYC-R.mjs.map +0 -1
- package/dist/search-CazwyX5Z.d.ts.map +0 -1
- package/dist/search-DUfWuzFP.js.map +0 -1
- package/dist/secret-config-BegMLkYl.mjs.map +0 -1
- package/dist/secret-config-CBZBs0p1.js.map +0 -1
- package/dist/slack.transport-Ce96JBDk.mjs.map +0 -1
- package/dist/slack.transport-Dlx3xvb7.js.map +0 -1
- package/dist/transport.manager-DkcEOlqV.js.map +0 -1
- package/dist/transport.manager-eZ_EeC00.mjs.map +0 -1
- package/dist/transport.types-BJVL1QQl.d.mts.map +0 -1
- package/dist/transport.types-BJVL1QQl.d.ts.map +0 -1
- package/dist/worker.transport-BuPwBi3d.d.ts.map +0 -1
- package/dist/worker.transport-C6GNl_r2.js.map +0 -1
- package/dist/worker.transport-DLVA4y2e.mjs.map +0 -1
- package/dist/worker.transport-hJay1wxA.d.mts.map +0 -1
package/dist/cli/index.js
CHANGED
|
@@ -83,6 +83,25 @@ function formatAsTable(rows, columns) {
|
|
|
83
83
|
rows.map((r) => columns.map((c, i) => cellText(r[c]).padEnd(colWidths[i] ?? 0)).join(" | ")).join("\n")
|
|
84
84
|
].join("\n");
|
|
85
85
|
}
|
|
86
|
+
/** Parse like {@link safeParseLogs} but keep each entry's original file line number. */
|
|
87
|
+
function parseLogLines(raw) {
|
|
88
|
+
const parsed = [];
|
|
89
|
+
for (const [i, text] of raw.split(/\r?\n/).entries()) {
|
|
90
|
+
if (!text) continue;
|
|
91
|
+
try {
|
|
92
|
+
parsed.push({
|
|
93
|
+
line: i + 1,
|
|
94
|
+
entry: JSON.parse(text)
|
|
95
|
+
});
|
|
96
|
+
} catch {
|
|
97
|
+
parsed.push({
|
|
98
|
+
line: i + 1,
|
|
99
|
+
entry: { message: text }
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
return parsed;
|
|
104
|
+
}
|
|
86
105
|
function safeParseLogs(raw) {
|
|
87
106
|
const lines = raw.split(/\r?\n/).filter(Boolean);
|
|
88
107
|
const parsed = [];
|
|
@@ -132,6 +151,7 @@ async function analyzeFileContents(raw, opts = {}) {
|
|
|
132
151
|
total: filtered.length,
|
|
133
152
|
byLevel
|
|
134
153
|
};
|
|
154
|
+
if (opts.format === "csv") return sanitizeForTerminal(["level,count", ...Object.keys(byLevel).map((k) => `${csvField(k)},${byLevel[k]}`)].join("\n"));
|
|
135
155
|
return formatAsTable(Object.keys(byLevel).map((k) => ({
|
|
136
156
|
level: k,
|
|
137
157
|
count: byLevel[k]
|
|
@@ -1029,7 +1049,7 @@ function matchesNode(row, node) {
|
|
|
1029
1049
|
}
|
|
1030
1050
|
function runAggregation(entries, agg) {
|
|
1031
1051
|
const { fn, field, groupBy } = agg;
|
|
1032
|
-
if (!groupBy) return
|
|
1052
|
+
if (!groupBy) return { warning: "Aggregation requires a GROUP BY field" };
|
|
1033
1053
|
const groups = /* @__PURE__ */ new Map();
|
|
1034
1054
|
for (const entry of entries) {
|
|
1035
1055
|
const key = String(entry[groupBy] ?? "(empty)");
|
|
@@ -1037,42 +1057,48 @@ function runAggregation(entries, agg) {
|
|
|
1037
1057
|
if (bucket) bucket.push(entry);
|
|
1038
1058
|
else groups.set(key, [entry]);
|
|
1039
1059
|
}
|
|
1040
|
-
if (fn === "COUNT" || fn === "GROUP") return
|
|
1041
|
-
[
|
|
1042
|
-
count: v.length
|
|
1043
|
-
})).sort((a, b) => b.count - a.count), [groupBy, "count"]);
|
|
1044
|
-
if (!field) return picocolors.default.yellow("Numeric aggregation requires a field: AVG(field) BY group");
|
|
1045
|
-
return formatAsTable([...groups.entries()].map(([k, v]) => {
|
|
1046
|
-
const nums = v.map((e) => Number(e[field])).filter((n) => !Number.isNaN(n));
|
|
1047
|
-
let result;
|
|
1048
|
-
switch (fn) {
|
|
1049
|
-
case "AVG":
|
|
1050
|
-
result = nums.length ? nums.reduce((a, b) => a + b, 0) / nums.length : 0;
|
|
1051
|
-
break;
|
|
1052
|
-
case "SUM":
|
|
1053
|
-
result = nums.reduce((a, b) => a + b, 0);
|
|
1054
|
-
break;
|
|
1055
|
-
case "MIN":
|
|
1056
|
-
result = nums.length ? Math.min(...nums) : 0;
|
|
1057
|
-
break;
|
|
1058
|
-
case "MAX":
|
|
1059
|
-
result = nums.length ? Math.max(...nums) : 0;
|
|
1060
|
-
break;
|
|
1061
|
-
default: result = 0;
|
|
1062
|
-
}
|
|
1063
|
-
return {
|
|
1060
|
+
if (fn === "COUNT" || fn === "GROUP") return {
|
|
1061
|
+
rows: [...groups.entries()].map(([k, v]) => ({
|
|
1064
1062
|
[groupBy]: k,
|
|
1065
|
-
[`${fn}(${field})`]: Math.round(result * 100) / 100,
|
|
1066
1063
|
count: v.length
|
|
1067
|
-
}
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1064
|
+
})).sort((a, b) => b.count - a.count),
|
|
1065
|
+
columns: [groupBy, "count"]
|
|
1066
|
+
};
|
|
1067
|
+
if (!field) return { warning: "Numeric aggregation requires a field: AVG(field) BY group" };
|
|
1068
|
+
return {
|
|
1069
|
+
rows: [...groups.entries()].map(([k, v]) => {
|
|
1070
|
+
const nums = v.map((e) => Number(e[field])).filter((n) => !Number.isNaN(n));
|
|
1071
|
+
let result;
|
|
1072
|
+
switch (fn) {
|
|
1073
|
+
case "AVG":
|
|
1074
|
+
result = nums.length ? nums.reduce((a, b) => a + b, 0) / nums.length : 0;
|
|
1075
|
+
break;
|
|
1076
|
+
case "SUM":
|
|
1077
|
+
result = nums.reduce((a, b) => a + b, 0);
|
|
1078
|
+
break;
|
|
1079
|
+
case "MIN":
|
|
1080
|
+
result = nums.length ? Math.min(...nums) : 0;
|
|
1081
|
+
break;
|
|
1082
|
+
case "MAX":
|
|
1083
|
+
result = nums.length ? Math.max(...nums) : 0;
|
|
1084
|
+
break;
|
|
1085
|
+
default: result = 0;
|
|
1086
|
+
}
|
|
1087
|
+
return {
|
|
1088
|
+
[groupBy]: k,
|
|
1089
|
+
[`${fn}(${field})`]: Math.round(result * 100) / 100,
|
|
1090
|
+
count: v.length
|
|
1091
|
+
};
|
|
1092
|
+
}).sort((a, b) => {
|
|
1093
|
+
const key = `${fn}(${field})`;
|
|
1094
|
+
return b[key] - a[key];
|
|
1095
|
+
}),
|
|
1096
|
+
columns: [
|
|
1097
|
+
groupBy,
|
|
1098
|
+
`${fn}(${field})`,
|
|
1099
|
+
"count"
|
|
1100
|
+
]
|
|
1101
|
+
};
|
|
1076
1102
|
}
|
|
1077
1103
|
function projectRow(row, select) {
|
|
1078
1104
|
if (select === "*") return row;
|
|
@@ -1080,6 +1106,11 @@ function projectRow(row, select) {
|
|
|
1080
1106
|
for (const field of select) projected[field] = row[field];
|
|
1081
1107
|
return projected;
|
|
1082
1108
|
}
|
|
1109
|
+
/** json prints an array (`[]` when empty); ndjson prints one row per line (nothing when empty). */
|
|
1110
|
+
function printMachineRows(rows, format) {
|
|
1111
|
+
if (format === "json") console.log(sanitizeForTerminal(JSON.stringify(rows, null, 2)));
|
|
1112
|
+
else if (rows.length > 0) console.log(rows.map((r) => sanitizeForTerminal(JSON.stringify(r))).join("\n"));
|
|
1113
|
+
}
|
|
1083
1114
|
function formatResults(results, format) {
|
|
1084
1115
|
if (results.length === 0) return picocolors.default.yellow("No results found");
|
|
1085
1116
|
if (format === "json") return sanitizeForTerminal(JSON.stringify(results, null, 2));
|
|
@@ -1114,10 +1145,19 @@ function executeQuery(entries, opts) {
|
|
|
1114
1145
|
limit: null
|
|
1115
1146
|
};
|
|
1116
1147
|
if (query.where) rows = rows.filter((row) => matchesWhere(row, query.where));
|
|
1117
|
-
if (query.aggregation)
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1148
|
+
if (query.aggregation) {
|
|
1149
|
+
const agg = runAggregation(rows, query.aggregation);
|
|
1150
|
+
if ("warning" in agg) return {
|
|
1151
|
+
results: [],
|
|
1152
|
+
aggregationOutput: picocolors.default.yellow(agg.warning),
|
|
1153
|
+
aggregationRows: []
|
|
1154
|
+
};
|
|
1155
|
+
return {
|
|
1156
|
+
results: [],
|
|
1157
|
+
aggregationOutput: formatAsTable(agg.rows, agg.columns),
|
|
1158
|
+
aggregationRows: agg.rows
|
|
1159
|
+
};
|
|
1160
|
+
}
|
|
1121
1161
|
const orderField = ((_query$orderBy = query.orderBy) === null || _query$orderBy === void 0 ? void 0 : _query$orderBy.field) ?? opts.orderBy;
|
|
1122
1162
|
if (orderField) {
|
|
1123
1163
|
var _query$orderBy2;
|
|
@@ -1139,7 +1179,8 @@ function executeQuery(entries, opts) {
|
|
|
1139
1179
|
rows = rows.map((row) => projectRow(row, query.select));
|
|
1140
1180
|
return {
|
|
1141
1181
|
results: rows,
|
|
1142
|
-
aggregationOutput: null
|
|
1182
|
+
aggregationOutput: null,
|
|
1183
|
+
aggregationRows: null
|
|
1143
1184
|
};
|
|
1144
1185
|
}
|
|
1145
1186
|
const queryCommand = new commander.Command("query").description("Query log files with SQL-like syntax\n\n Examples:\n logixia query app.log --sql \"SELECT * FROM logs WHERE level='error'\"\n logixia query app.log --sql \"COUNT BY level\"\n logixia query app.log --sql \"AVG(duration) BY endpoint\"\n logixia query app.log --since \"last 2 hours\" --format table\n logixia query app.log --follow --sql \"WHERE level='error'\"\n").argument("<file>", "Path to NDJSON or JSON log file").option("--sql <query>", "SQL-like query string").option("--since <time>", "Only include entries after this time (e.g. \"last 2 hours\", \"today\")").option("--until <time>", "Only include entries before this time").option("--limit <n>", "Maximum number of results to return").option("--order-by <field>", "Sort results by this field").option("--format <fmt>", "Output format: line, table, json, ndjson", "line").option("--follow", "Follow file for new entries matching the query (tail mode)", false).action(async (file, opts) => {
|
|
@@ -1151,22 +1192,26 @@ const queryCommand = new commander.Command("query").description("Query log files
|
|
|
1151
1192
|
const entries = safeParseLogs(node_fs.default.readFileSync(full, "utf8"));
|
|
1152
1193
|
const parsedLimit = opts.limit === void 0 ? NaN : Number.parseInt(opts.limit, 10);
|
|
1153
1194
|
const limitN = Number.isNaN(parsedLimit) ? void 0 : parsedLimit;
|
|
1154
|
-
const { results, aggregationOutput } = executeQuery(entries, {
|
|
1195
|
+
const { results, aggregationOutput, aggregationRows } = executeQuery(entries, {
|
|
1155
1196
|
sql: opts.sql,
|
|
1156
1197
|
since: opts.since,
|
|
1157
1198
|
until: opts.until,
|
|
1158
1199
|
limit: limitN,
|
|
1159
1200
|
orderBy: opts.orderBy
|
|
1160
1201
|
});
|
|
1202
|
+
const machineFormat = opts.format === "json" || opts.format === "ndjson";
|
|
1203
|
+
const status = machineFormat ? console.error : console.log;
|
|
1161
1204
|
if (aggregationOutput !== null) {
|
|
1162
|
-
|
|
1163
|
-
|
|
1205
|
+
status(picocolors.default.bold("\nAggregation result:"));
|
|
1206
|
+
if (machineFormat) printMachineRows(aggregationRows ?? [], opts.format);
|
|
1207
|
+
else console.log(aggregationOutput);
|
|
1164
1208
|
} else {
|
|
1165
|
-
|
|
1166
|
-
if (
|
|
1209
|
+
status(picocolors.default.bold(`\nFound ${picocolors.default.cyan(String(results.length))} match${results.length === 1 ? "" : "es"}`));
|
|
1210
|
+
if (machineFormat) printMachineRows(results, opts.format);
|
|
1211
|
+
else if (results.length > 0) console.log(formatResults(results, opts.format || "line"));
|
|
1167
1212
|
}
|
|
1168
1213
|
if (opts.follow) {
|
|
1169
|
-
|
|
1214
|
+
status(picocolors.default.dim("\n--- following (ctrl-c to exit) ---"));
|
|
1170
1215
|
let pos = node_fs.default.statSync(full).size;
|
|
1171
1216
|
let buffer = "";
|
|
1172
1217
|
node_fs.default.watchFile(full, { interval: 300 }, (curr) => {
|
|
@@ -1206,31 +1251,76 @@ function parseQuery(query) {
|
|
|
1206
1251
|
};
|
|
1207
1252
|
return { value: query };
|
|
1208
1253
|
}
|
|
1209
|
-
|
|
1210
|
-
const
|
|
1211
|
-
const
|
|
1212
|
-
return
|
|
1254
|
+
function entryMatcher(query) {
|
|
1255
|
+
const criteria = parseQuery(query);
|
|
1256
|
+
const needle = criteria.value.toLowerCase();
|
|
1257
|
+
return (entry) => {
|
|
1213
1258
|
const row = entry;
|
|
1214
1259
|
if (criteria.field) {
|
|
1215
1260
|
const fieldValue = row[criteria.field];
|
|
1216
1261
|
if (fieldValue === void 0) return false;
|
|
1217
|
-
return String(fieldValue).toLowerCase().includes(
|
|
1218
|
-
}
|
|
1219
|
-
|
|
1262
|
+
return String(fieldValue).toLowerCase().includes(needle);
|
|
1263
|
+
}
|
|
1264
|
+
return JSON.stringify(row).toLowerCase().includes(needle);
|
|
1265
|
+
};
|
|
1220
1266
|
}
|
|
1221
|
-
|
|
1222
|
-
|
|
1267
|
+
/**
|
|
1268
|
+
* Like grep -C: matches plus `context` parsed entries (blank lines are skipped) before and
|
|
1269
|
+
* after each, in file order, tagged with their original file line numbers. Single pass.
|
|
1270
|
+
*/
|
|
1271
|
+
async function searchLogsWithContext(raw, opts = {}) {
|
|
1272
|
+
const parsed = parseLogLines(raw);
|
|
1273
|
+
const isMatch = entryMatcher(opts.query || "");
|
|
1274
|
+
const context = Math.max(0, Number.parseInt(String(opts.context ?? 0), 10) || 0);
|
|
1275
|
+
const matched = parsed.map((p) => isMatch(p.entry));
|
|
1276
|
+
const nextMatch = Array.from({ length: parsed.length }, () => Number.POSITIVE_INFINITY);
|
|
1277
|
+
let next = Number.POSITIVE_INFINITY;
|
|
1278
|
+
for (let i = parsed.length - 1; i >= 0; i--) {
|
|
1279
|
+
if (matched[i]) next = i;
|
|
1280
|
+
nextMatch[i] = next;
|
|
1281
|
+
}
|
|
1282
|
+
const hits = [];
|
|
1283
|
+
let lastMatch = Number.NEGATIVE_INFINITY;
|
|
1284
|
+
for (const [i, p] of parsed.entries()) {
|
|
1285
|
+
if (matched[i]) lastMatch = i;
|
|
1286
|
+
if (i - lastMatch <= context || nextMatch[i] - i <= context) hits.push({
|
|
1287
|
+
index: i,
|
|
1288
|
+
line: p.line,
|
|
1289
|
+
entry: p.entry,
|
|
1290
|
+
match: Boolean(matched[i])
|
|
1291
|
+
});
|
|
1292
|
+
}
|
|
1293
|
+
return hits;
|
|
1294
|
+
}
|
|
1295
|
+
function matchedColumns(hits) {
|
|
1296
|
+
const cols = /* @__PURE__ */ new Set();
|
|
1297
|
+
for (const h of hits) if (h.match) for (const k of Object.keys(h.entry || {})) cols.add(k);
|
|
1298
|
+
if (cols.size === 0) for (const h of hits) for (const k of Object.keys(h.entry || {})) cols.add(k);
|
|
1299
|
+
return [...cols].slice(0, 4);
|
|
1300
|
+
}
|
|
1301
|
+
function formatSearchResults(hits, format) {
|
|
1302
|
+
if (format === "json") return sanitizeForTerminal(JSON.stringify(hits.filter((h) => h.match).map((h) => h.entry), null, 2));
|
|
1303
|
+
if (hits.length === 0) return picocolors.default.yellow("No results found");
|
|
1223
1304
|
if (format === "table") {
|
|
1224
|
-
|
|
1225
|
-
|
|
1305
|
+
const withContext = hits.some((h) => !h.match);
|
|
1306
|
+
const rows = hits.map((h) => withContext ? {
|
|
1307
|
+
match: h.match ? "*" : "",
|
|
1308
|
+
...h.entry
|
|
1309
|
+
} : h.entry);
|
|
1310
|
+
const columns = matchedColumns(hits);
|
|
1311
|
+
return formatAsTable(rows, withContext ? ["match", ...columns] : columns);
|
|
1226
1312
|
}
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1313
|
+
const lines = [];
|
|
1314
|
+
let prev = -1;
|
|
1315
|
+
for (const h of hits) {
|
|
1316
|
+
if (prev >= 0 && h.index > prev + 1) lines.push(picocolors.default.gray("--"));
|
|
1317
|
+
prev = h.index;
|
|
1318
|
+
const sep = h.match ? ":" : "-";
|
|
1319
|
+
lines.push(`${picocolors.default.gray(String(h.line) + sep)} ${sanitizeForTerminal(JSON.stringify(h.entry))}`);
|
|
1320
|
+
}
|
|
1321
|
+
return lines.join("\n");
|
|
1232
1322
|
}
|
|
1233
|
-
const searchCommand = new commander.Command("search").description("Search log files with query patterns").argument("<file>", "Path to log file").option("--query <query>", "Search query (e.g., \"user_id:123\" or \"error\")", "").option("--format <fmt>", "Output format (table, json, line)", "line").option("--context <lines>", "
|
|
1323
|
+
const searchCommand = new commander.Command("search").description("Search log files with query patterns").argument("<file>", "Path to log file").option("--query <query>", "Search query (e.g., \"user_id:123\" or \"error\")", "").option("--format <fmt>", "Output format (table, json, line)", "line").option("--context <lines>", "Entries of context around each match (line/table formats)", "0").action(async (file, opts) => {
|
|
1234
1324
|
const full = node_path.default.resolve(process.cwd(), file);
|
|
1235
1325
|
if (!node_fs.default.existsSync(full)) {
|
|
1236
1326
|
console.error(`File not found: ${full}`);
|
|
@@ -1240,9 +1330,10 @@ const searchCommand = new commander.Command("search").description("Search log fi
|
|
|
1240
1330
|
console.error("--query is required");
|
|
1241
1331
|
process.exit(2);
|
|
1242
1332
|
}
|
|
1243
|
-
const
|
|
1244
|
-
|
|
1245
|
-
|
|
1333
|
+
const hits = await searchLogsWithContext(node_fs.default.readFileSync(full, "utf8"), opts);
|
|
1334
|
+
const count = hits.filter((h) => h.match).length;
|
|
1335
|
+
(opts.format === "json" ? console.error : console.log)(picocolors.default.bold(`\nFound ${count} matches`));
|
|
1336
|
+
console.log(formatSearchResults(hits, opts.format));
|
|
1246
1337
|
});
|
|
1247
1338
|
// src/cli/commands/stats.ts
|
|
1248
1339
|
async function generateStats(raw, opts = {}) {
|
package/dist/cloudwatch.d.mts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { n as CloudWatchTransportConfig, t as CloudWatchTransport } from "./cloudwatch.transport-
|
|
1
|
+
import { n as CloudWatchTransportConfig, t as CloudWatchTransport } from "./cloudwatch.transport-CjVrI6S4.mjs";
|
|
2
2
|
export { CloudWatchTransport, CloudWatchTransportConfig };
|
package/dist/cloudwatch.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { n as CloudWatchTransportConfig, t as CloudWatchTransport } from "./cloudwatch.transport-
|
|
1
|
+
import { n as CloudWatchTransportConfig, t as CloudWatchTransport } from "./cloudwatch.transport-CQyT6U91.js";
|
|
2
2
|
export { CloudWatchTransport, CloudWatchTransportConfig };
|
package/dist/cloudwatch.js
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
-
const require_cloudwatch_transport = require("./cloudwatch.transport-
|
|
2
|
+
const require_cloudwatch_transport = require("./cloudwatch.transport-D4G5xYfG.js");
|
|
3
3
|
exports.CloudWatchTransport = require_cloudwatch_transport.CloudWatchTransport;
|
package/dist/cloudwatch.mjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export { t as CloudWatchTransport } from "./cloudwatch.transport-
|
|
1
|
+
export { t as CloudWatchTransport } from "./cloudwatch.transport-Cr1aeTGj.mjs";
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { _ as TransportLogEntry, l as IAsyncTransport } from "./transport.types-CzJq4IrF.js";
|
|
2
2
|
interface CloudWatchTransportConfig {
|
|
3
3
|
/** AWS region, e.g. `'us-east-1'`. Falls back to `AWS_REGION` env var. */
|
|
4
4
|
region?: string;
|
|
@@ -81,4 +81,4 @@ declare class CloudWatchTransport implements IAsyncTransport {
|
|
|
81
81
|
private call;
|
|
82
82
|
}
|
|
83
83
|
export { CloudWatchTransportConfig as n, CloudWatchTransport as t };
|
|
84
|
-
//# sourceMappingURL=cloudwatch.transport-
|
|
84
|
+
//# sourceMappingURL=cloudwatch.transport-CQyT6U91.d.ts.map
|
package/dist/{cloudwatch.transport-Bf7L4I59.d.ts.map → cloudwatch.transport-CQyT6U91.d.ts.map}
RENAMED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cloudwatch.transport-
|
|
1
|
+
{"version":3,"file":"cloudwatch.transport-CQyT6U91.d.ts","names":[],"sources":["../src/transports/cloudwatch.transport.ts"],"mappings":";UAmDiB;;EAEf;;EAEA;;EAEA;;EAEA;;EAEA;;EAEA;;EAEA;;;;;;EAMA;;;;;EAKA;;;;;;EAMA;;EAEA;;;;;;EAMA;;EAEA;;EAEA;;EAEA;;;;;cAkCW,+BAA+B;WAC1B;WACA;WACA;WACA;mBAEC;mBACA;UACT;mBACS;mBACA;UACT;mBAES;mBACA;mBACA;mBACA;mBACA;mBACA;EAEL,YAAA,QAAQ;EAmCpB,MAAM,OAAO;EAOb,SAAS;;;;;;EASH,SAAS;UAQP;UAyBM;UAkBA;UAsBA"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { _ as TransportLogEntry, l as IAsyncTransport } from "./transport.types-CzJq4IrF.mjs";
|
|
2
2
|
interface CloudWatchTransportConfig {
|
|
3
3
|
/** AWS region, e.g. `'us-east-1'`. Falls back to `AWS_REGION` env var. */
|
|
4
4
|
region?: string;
|
|
@@ -81,4 +81,4 @@ declare class CloudWatchTransport implements IAsyncTransport {
|
|
|
81
81
|
private call;
|
|
82
82
|
}
|
|
83
83
|
export { CloudWatchTransportConfig as n, CloudWatchTransport as t };
|
|
84
|
-
//# sourceMappingURL=cloudwatch.transport-
|
|
84
|
+
//# sourceMappingURL=cloudwatch.transport-CjVrI6S4.d.mts.map
|
package/dist/{cloudwatch.transport-Rj4yTpRn.d.mts.map → cloudwatch.transport-CjVrI6S4.d.mts.map}
RENAMED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cloudwatch.transport-
|
|
1
|
+
{"version":3,"file":"cloudwatch.transport-CjVrI6S4.d.mts","names":[],"sources":["../src/transports/cloudwatch.transport.ts"],"mappings":";UAmDiB;;EAEf;;EAEA;;EAEA;;EAEA;;EAEA;;EAEA;;EAEA;;;;;;EAMA;;;;;EAKA;;;;;;EAMA;;EAEA;;;;;;EAMA;;EAEA;;EAEA;;EAEA;;;;;cAkCW,+BAA+B;WAC1B;WACA;WACA;WACA;mBAEC;mBACA;UACT;mBACS;mBACA;UACT;mBAES;mBACA;mBACA;mBACA;mBACA;mBACA;EAEL,YAAA,QAAQ;EAmCpB,MAAM,OAAO;EAOb,SAAS;;;;;;EASH,SAAS;UAQP;UAyBM;UAkBA;UAsBA"}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import { i as stringifyForLog } from "./safe-stringify
|
|
4
|
-
import { t as mergeCoreFields } from "./entry-fields-
|
|
5
|
-
import { a as httpRequest, i as HttpError, o as isPermanentHttpError, t as BatchBuffer } from "./batch-buffer-
|
|
1
|
+
import { n as protectSecrets, o as urlSecrets } from "./secret-config-ByGq7kJd.mjs";
|
|
2
|
+
import { r as internalWarn } from "./internal-log-Cy5nF1ZL.mjs";
|
|
3
|
+
import { i as stringifyForLog } from "./safe-stringify--7gbe95n.mjs";
|
|
4
|
+
import { t as mergeCoreFields } from "./entry-fields-DNTKQxoU.mjs";
|
|
5
|
+
import { a as httpRequest, i as HttpError, o as isPermanentHttpError, t as BatchBuffer } from "./batch-buffer-CQUWDMYq.mjs";
|
|
6
6
|
import * as crypto from "node:crypto";
|
|
7
7
|
import * as os from "node:os";
|
|
8
8
|
import * as fs from "node:fs";
|
|
@@ -390,4 +390,4 @@ var CloudWatchTransport = class {
|
|
|
390
390
|
};
|
|
391
391
|
export { CloudWatchTransport as t };
|
|
392
392
|
|
|
393
|
-
//# sourceMappingURL=cloudwatch.transport-
|
|
393
|
+
//# sourceMappingURL=cloudwatch.transport-Cr1aeTGj.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cloudwatch.transport-Cr1aeTGj.mjs","names":["path"],"sources":["../src/transports/aws-credentials.ts","../src/transports/aws-sigv4.ts","../src/transports/cloudwatch.transport.ts"],"sourcesContent":["/**\n * AWS credential resolution without the SDK.\n *\n * Order: explicit config, environment variables, shared credentials file,\n * ECS/container credentials, EC2 instance metadata (IMDSv2).\n * Not supported: SSO, assume-role profiles, credential_process, web identity.\n */\n\nimport * as fs from 'node:fs';\nimport * as os from 'node:os';\nimport * as path from 'node:path';\n\nimport { internalWarn } from '../utils/internal-log';\nimport { type AwsCredentials } from './aws-sigv4';\nimport { httpRequest } from './batch-buffer';\nimport { protectSecrets } from './secret-config';\n\nconst REFRESH_MARGIN_MS = 5 * 60 * 1000;\nconst FAILURE_BACKOFF_MS = 30 * 1000;\nconst METADATA_TIMEOUT_MS = 2000;\n\nexport interface AwsCredentialConfig {\n accessKeyId?: string | undefined;\n secretAccessKey?: string | undefined;\n sessionToken?: string | undefined;\n}\n\n/** Parse the sections of an AWS ini file into `{ section: { key: value } }`. */\nexport function parseIni(text: string): Record<string, Record<string, string>> {\n const out: Record<string, Record<string, string>> = {};\n let section: Record<string, string> | undefined;\n for (const raw of text.split(/\\r?\\n/)) {\n const line = raw.trim();\n if (!line || line.startsWith('#') || line.startsWith(';')) continue;\n const header = /^\\[(.+)\\]$/.exec(line);\n if (header) {\n section = out[header[1]!.trim()] = out[header[1]!.trim()] ?? {};\n continue;\n }\n const eq = line.indexOf('=');\n if (eq > 0 && section) section[line.slice(0, eq).trim()] = line.slice(eq + 1).trim();\n }\n return out;\n}\n\nfunction fromEnv(): AwsCredentials | undefined {\n const accessKeyId = process.env['AWS_ACCESS_KEY_ID'];\n const secretAccessKey = process.env['AWS_SECRET_ACCESS_KEY'];\n if (!accessKeyId || !secretAccessKey) return undefined;\n return { accessKeyId, secretAccessKey, sessionToken: process.env['AWS_SESSION_TOKEN'] };\n}\n\nfunction fromSharedFile(): AwsCredentials | undefined {\n const file =\n process.env['AWS_SHARED_CREDENTIALS_FILE'] ?? path.join(os.homedir(), '.aws', 'credentials');\n const profile = process.env['AWS_PROFILE'] ?? 'default';\n let text: string;\n try {\n text = fs.readFileSync(file, 'utf8');\n } catch {\n return undefined;\n }\n const section = parseIni(text)[profile];\n const accessKeyId = section?.['aws_access_key_id'];\n const secretAccessKey = section?.['aws_secret_access_key'];\n if (!accessKeyId || !secretAccessKey) return undefined;\n return { accessKeyId, secretAccessKey, sessionToken: section?.['aws_session_token'] };\n}\n\ninterface CredentialDocument {\n AccessKeyId?: string;\n SecretAccessKey?: string;\n Token?: string;\n Expiration?: string;\n}\n\nfunction fromDocument(raw: string): AwsCredentials | undefined {\n const doc = JSON.parse(raw) as CredentialDocument;\n if (!doc.AccessKeyId || !doc.SecretAccessKey) return undefined;\n const expiresAt = doc.Expiration ? Date.parse(doc.Expiration) : Number.NaN;\n return {\n accessKeyId: doc.AccessKeyId,\n secretAccessKey: doc.SecretAccessKey,\n sessionToken: doc.Token,\n expiresAt: Number.isNaN(expiresAt) ? undefined : expiresAt,\n };\n}\n\nconst CONTAINER_HOSTS = new Set([\n // eslint-disable-next-line sonarjs/no-hardcoded-ip -- fixed ECS credentials endpoint\n '169.254.170.2',\n // eslint-disable-next-line sonarjs/no-hardcoded-ip -- fixed EKS pod identity endpoint\n '169.254.170.23',\n '[fd00:ec2::23]',\n 'localhost',\n '[::1]',\n]);\n\n/** Same rule as the AWS SDKs: never send the container token to an arbitrary http host. */\nfunction isAllowedContainerHost(url: URL): boolean {\n if (url.protocol === 'https:') return true;\n if (url.protocol !== 'http:') return false;\n return CONTAINER_HOSTS.has(url.hostname) || /^127(?:\\.\\d{1,3}){3}$/.test(url.hostname);\n}\n\nasync function fromContainer(): Promise<AwsCredentials | undefined> {\n const relative = process.env['AWS_CONTAINER_CREDENTIALS_RELATIVE_URI'];\n const full = process.env['AWS_CONTAINER_CREDENTIALS_FULL_URI'];\n if (!relative && !full) return undefined;\n const url = new URL(relative ? `http://169.254.170.2${relative}` : (full as string));\n if (!relative && !isAllowedContainerHost(url)) {\n internalWarn(\n `ignoring AWS_CONTAINER_CREDENTIALS_FULL_URI: ${url.host} is not https or a loopback / ECS / EKS address`\n );\n return undefined;\n }\n const headers: Record<string, string> = {};\n const tokenFile = process.env['AWS_CONTAINER_AUTHORIZATION_TOKEN_FILE'];\n const token = tokenFile\n ? fs.readFileSync(tokenFile, 'utf8').trim()\n : process.env['AWS_CONTAINER_AUTHORIZATION_TOKEN'];\n if (token) headers['Authorization'] = token;\n const res = await httpRequest({\n url,\n method: 'GET',\n headers,\n timeoutMs: METADATA_TIMEOUT_MS,\n label: 'AWS container credentials',\n });\n return fromDocument(res.body);\n}\n\nasync function fromInstanceMetadata(): Promise<AwsCredentials | undefined> {\n if (process.env['AWS_EC2_METADATA_DISABLED'] === 'true') return undefined;\n const base = process.env['AWS_EC2_METADATA_SERVICE_ENDPOINT'] ?? 'http://169.254.169.254';\n const get = (p: string, method: string, headers: Record<string, string>) =>\n httpRequest({\n url: new URL(p, base),\n method,\n headers,\n timeoutMs: METADATA_TIMEOUT_MS,\n label: 'EC2 instance metadata',\n });\n const session = await get('/latest/api/token', 'PUT', {\n 'X-aws-ec2-metadata-token-ttl-seconds': '21600',\n });\n const auth = { 'X-aws-ec2-metadata-token': session.body.trim() };\n const roles = await get('/latest/meta-data/iam/security-credentials/', 'GET', auth);\n const role = roles.body.split('\\n')[0]?.trim();\n if (!role) return undefined;\n const creds = await get(\n `/latest/meta-data/iam/security-credentials/${encodeURIComponent(role)}`,\n 'GET',\n auth\n );\n return fromDocument(creds.body);\n}\n\nexport class AwsCredentialProvider {\n private cached: AwsCredentials | undefined;\n private failedAt = 0;\n private readonly explicit: AwsCredentials | undefined;\n\n constructor(config: AwsCredentialConfig) {\n protectSecrets(this, ['cached', 'explicit']);\n if (config.accessKeyId && config.secretAccessKey) {\n this.explicit = {\n accessKeyId: config.accessKeyId,\n secretAccessKey: config.secretAccessKey,\n sessionToken: config.sessionToken,\n };\n }\n }\n\n /** Throws when no source yields credentials, so the caller keeps its buffer. */\n async get(): Promise<AwsCredentials> {\n if (this.explicit) return this.explicit;\n const env = fromEnv();\n if (env) return env;\n if (this.cached && !this.isExpiring(this.cached)) return this.cached;\n if (Date.now() - this.failedAt < FAILURE_BACKOFF_MS) {\n throw new Error('no AWS credentials found (retrying shortly)');\n }\n\n let found = fromSharedFile();\n for (const source of [fromContainer, fromInstanceMetadata]) {\n if (found) break;\n try {\n found = await source();\n } catch {\n /* source not available here; try the next */\n }\n }\n if (!found) {\n this.failedAt = Date.now();\n throw new Error(\n 'no AWS credentials found: set AWS_ACCESS_KEY_ID/AWS_SECRET_ACCESS_KEY, a shared credentials file, container credentials, or run on EC2 with an instance role'\n );\n }\n this.cached = found;\n return found;\n }\n\n /** Secret values this provider may hold, for scrubbing error text. */\n secretValues(): (string | undefined)[] {\n const env = process.env;\n return [\n this.explicit?.secretAccessKey,\n this.explicit?.sessionToken,\n this.cached?.secretAccessKey,\n this.cached?.sessionToken,\n env['AWS_SECRET_ACCESS_KEY'],\n env['AWS_SESSION_TOKEN'],\n ];\n }\n\n invalidate(): void {\n this.cached = undefined;\n this.failedAt = 0;\n }\n\n private isExpiring(c: AwsCredentials): boolean {\n return c.expiresAt !== undefined && c.expiresAt - Date.now() < REFRESH_MARGIN_MS;\n }\n}\n","/**\n * AWS Signature Version 4 request signing, dependency-free.\n */\n\nimport * as crypto from 'node:crypto';\n\nexport interface AwsCredentials {\n accessKeyId: string;\n secretAccessKey: string;\n sessionToken?: string | undefined;\n /** Epoch ms after which the credentials are no longer valid. */\n expiresAt?: number | undefined;\n}\n\nexport interface SignV4Options {\n method: string;\n path: string;\n query?: string;\n /** Must include `host`. Names are lowercased before signing. */\n headers: Record<string, string>;\n body: string;\n region: string;\n service: string;\n credentials: AwsCredentials;\n date?: Date;\n}\n\nconst sha256Hex = (data: string): string => crypto.createHash('sha256').update(data).digest('hex');\n\nconst hmac = (key: Buffer | string, msg: string): Buffer =>\n crypto.createHmac('sha256', key).update(msg).digest();\n\n/** Returns the request headers (lowercase names) with `x-amz-date` and `authorization` added. */\nexport function signV4(opts: SignV4Options): Record<string, string> {\n const {\n method,\n path,\n query = '',\n body,\n region,\n service,\n credentials,\n headers: input,\n date,\n } = opts;\n const amzDate = (date ?? new Date()).toISOString().replace(/[:-]|\\.\\d{3}/g, '');\n const dateStamp = amzDate.slice(0, 8);\n\n const headers: Record<string, string> = {};\n for (const [k, v] of Object.entries(input)) headers[k.toLowerCase()] = v;\n headers['x-amz-date'] = amzDate;\n if (credentials.sessionToken) headers['x-amz-security-token'] = credentials.sessionToken;\n\n const names = Object.keys(headers).sort();\n const canonicalHeaders = names\n .map((n) => `${n}:${headers[n]!.trim().replace(/\\s+/g, ' ')}\\n`)\n .join('');\n const signedHeaders = names.join(';');\n\n const canonicalRequest = [\n method,\n path,\n query,\n canonicalHeaders,\n signedHeaders,\n sha256Hex(body),\n ].join('\\n');\n const scope = `${dateStamp}/${region}/${service}/aws4_request`;\n const stringToSign = ['AWS4-HMAC-SHA256', amzDate, scope, sha256Hex(canonicalRequest)].join('\\n');\n\n const signingKey = hmac(\n hmac(hmac(hmac(`AWS4${credentials.secretAccessKey}`, dateStamp), region), service),\n 'aws4_request'\n );\n const signature = crypto.createHmac('sha256', signingKey).update(stringToSign).digest('hex');\n\n headers['authorization'] =\n `AWS4-HMAC-SHA256 Credential=${credentials.accessKeyId}/${scope}, ` +\n `SignedHeaders=${signedHeaders}, Signature=${signature}`;\n return headers;\n}\n","/**\n * logixia — AWS CloudWatch Logs transport\n *\n * Sends log entries to AWS CloudWatch Logs via the PutLogEvents API.\n * Supports EMF (Embedded Metric Format) for automatic metric extraction.\n *\n * Auth, in order: explicit config, environment variables, the shared\n * credentials file (AWS_PROFILE, AWS_SHARED_CREDENTIALS_FILE), ECS container\n * credentials, then EC2 instance metadata (IMDSv2). SSO, assume-role profiles\n * and credential_process are not supported. No SDK dependency — raw HTTPS with\n * AWS Signature Version 4.\n *\n * The log group and stream are created on first use if they do not exist.\n *\n * @example\n * ```ts\n * import { createLogger } from 'logixia';\n * import { CloudWatchTransport } from 'logixia/cloudwatch';\n *\n * const logger = createLogger({\n * transports: {\n * custom: [\n * new CloudWatchTransport({\n * region: 'us-east-1',\n * logGroupName: '/myapp/production',\n * logStreamName: `api-${process.env.HOSTNAME}`,\n * batchSize: 100,\n * flushIntervalMs: 5000,\n * }),\n * ],\n * },\n * });\n * ```\n */\n\nimport type { IAsyncTransport, TransportLogEntry } from '../types/transport.types';\nimport { internalWarn } from '../utils/internal-log';\nimport { stringifyForLog } from '../utils/safe-stringify';\nimport { AwsCredentialProvider } from './aws-credentials';\nimport { signV4 } from './aws-sigv4';\nimport {\n BatchBuffer,\n DEFAULT_MAX_BUFFER_SIZE,\n DEFAULT_REQUEST_TIMEOUT_MS,\n HttpError,\n httpRequest,\n isPermanentHttpError,\n} from './batch-buffer';\nimport { mergeCoreFields } from './entry-fields';\nimport { protectSecrets, urlSecrets } from './secret-config';\n\nexport interface CloudWatchTransportConfig {\n /** AWS region, e.g. `'us-east-1'`. Falls back to `AWS_REGION` env var. */\n region?: string;\n /** CloudWatch Logs group name. Created automatically if it does not exist. */\n logGroupName: string;\n /** CloudWatch Logs stream name. Defaults to hostname + process PID. */\n logStreamName?: string;\n /** Override the Logs endpoint, e.g. for LocalStack. Default: `https://logs.<region>.amazonaws.com`. */\n endpoint?: string;\n /** AWS access key ID. Falls back to the credential chain described above. */\n accessKeyId?: string;\n /** AWS secret access key. Used together with `accessKeyId`. */\n secretAccessKey?: string;\n /** AWS session token for temporary credentials. Used together with `accessKeyId`. */\n sessionToken?: string;\n /**\n * Number of log events to batch before flushing.\n * CloudWatch allows max 10,000 events per PutLogEvents call; larger values are capped.\n * @default 100\n */\n batchSize?: number;\n /**\n * Max ms between flushes even if batchSize is not reached.\n * @default 5000\n */\n flushIntervalMs?: number;\n /**\n * Enable EMF (Embedded Metric Format) — wraps log entries as CloudWatch\n * metric namespaces so numeric fields become CloudWatch Metrics automatically.\n * @default false\n */\n emf?: boolean;\n /** CloudWatch Metrics namespace used by EMF. @default 'Logixia' */\n emfNamespace?: string;\n /**\n * Payload fields published as EMF metrics. When set, only these numeric\n * fields become metrics; when unset every numeric payload field does (up to\n * the EMF limit of 100 per entry).\n */\n emfMetrics?: string[];\n /** Abort a request that has not finished after this many ms. @default 10000 */\n requestTimeoutMs?: number;\n /** Max buffered events; the oldest are dropped past this. @default 10000 */\n maxBufferSize?: number;\n /** Minimum log level to forward. */\n level?: string;\n}\n\nconst MAX_EVENTS_PER_PUT = 10_000;\nconst EMF_MAX_METRICS = 100;\n\n/** Error types worth retrying even though CloudWatch reports them as HTTP 400. */\nconst RETRYABLE_TYPES = new Set([\n 'ThrottlingException',\n 'ThrottledException',\n 'LimitExceededException',\n 'ServiceUnavailableException',\n 'ExpiredTokenException',\n 'ResourceNotFoundException',\n]);\n\nfunction awsErrorType(err: unknown): string | undefined {\n if (!(err instanceof HttpError)) return undefined;\n try {\n const type = (JSON.parse(err.body) as { __type?: string }).__type;\n return type?.split('#').pop();\n } catch {\n return undefined;\n }\n}\n\ninterface CwLogEvent {\n timestamp: number;\n message: string;\n}\n\n/**\n * AWS CloudWatch Logs transport with EMF support and batched PutLogEvents calls.\n */\nexport class CloudWatchTransport implements IAsyncTransport {\n public readonly name = 'cloudwatch';\n public readonly batchSize: number;\n public readonly flushInterval: number;\n public readonly level: string | undefined;\n\n private readonly buffer: BatchBuffer<CwLogEvent>;\n private readonly requestTimeoutMs: number;\n private flushTimer: NodeJS.Timeout | null = null;\n private readonly credentials: AwsCredentialProvider;\n private readonly endpoint: URL;\n private streamReady = false;\n\n private readonly region: string;\n private readonly logGroupName: string;\n private readonly logStreamName: string;\n private readonly emf: boolean;\n private readonly emfNamespace: string;\n private readonly emfMetrics: ReadonlySet<string> | undefined;\n\n constructor(config: CloudWatchTransportConfig) {\n this.region =\n config.region ??\n process.env['AWS_REGION'] ??\n process.env['AWS_DEFAULT_REGION'] ??\n 'us-east-1';\n this.logGroupName = config.logGroupName;\n this.logStreamName =\n config.logStreamName ?? `${process.env['HOSTNAME'] ?? 'node'}-${process.pid}`;\n this.credentials = new AwsCredentialProvider(config);\n this.endpoint = new URL(config.endpoint ?? `https://logs.${this.region}.amazonaws.com`);\n this.batchSize = Math.min(config.batchSize ?? 100, MAX_EVENTS_PER_PUT);\n this.emfNamespace = config.emfNamespace ?? 'Logixia';\n this.flushInterval = config.flushIntervalMs ?? 5000;\n this.emf = config.emf ?? false;\n this.emfMetrics = config.emfMetrics ? new Set(config.emfMetrics) : undefined;\n this.level = config.level;\n this.requestTimeoutMs = config.requestTimeoutMs ?? DEFAULT_REQUEST_TIMEOUT_MS;\n this.buffer = new BatchBuffer<CwLogEvent>({\n name: 'CloudWatchTransport',\n batchSize: this.batchSize,\n maxBufferSize: config.maxBufferSize ?? DEFAULT_MAX_BUFFER_SIZE,\n send: (events) => this.putLogEvents(events),\n secrets: () => [...this.credentials.secretValues(), ...urlSecrets(this.endpoint)],\n shouldRetry: (err) =>\n !isPermanentHttpError(err) || RETRYABLE_TYPES.has(awsErrorType(err) ?? ''),\n });\n\n this.flushTimer = setInterval(() => {\n this.flush().catch(() => {});\n }, this.flushInterval);\n if (this.flushTimer.unref) this.flushTimer.unref();\n protectSecrets(this, ['credentials', 'endpoint']);\n }\n\n write(entry: TransportLogEntry): void {\n const timestamp = entry.timestamp ? new Date(entry.timestamp).getTime() : Date.now();\n const message = this.emf ? this.toEmf(entry) : stringifyForLog(entry);\n this.buffer.push({ timestamp, message });\n this.buffer.flushIfFull();\n }\n\n flush(): Promise<void> {\n return this.buffer.flush();\n }\n\n /**\n * Flush remaining events and stop the interval timer on shutdown. Without this\n * the manager's close() skips the transport (close was undefined) and any\n * buffered events were lost on deploy. Waits for any in-flight send first.\n */\n async close(): Promise<void> {\n if (this.flushTimer) {\n clearInterval(this.flushTimer);\n this.flushTimer = null;\n }\n await this.buffer.close();\n }\n\n private toEmf(entry: TransportLogEntry): string {\n const { level, message, data: payload, timestamp } = entry;\n const fields = mergeCoreFields({ _aws: undefined, level, message }, payload);\n const metricNames: string[] = [];\n for (const [k, v] of Object.entries(fields)) {\n if (k === '_aws' || k === 'level' || k === 'message' || typeof v !== 'number') continue;\n if (this.emfMetrics && !this.emfMetrics.has(k)) continue;\n if (metricNames.length < EMF_MAX_METRICS) metricNames.push(k);\n }\n fields['_aws'] = {\n Timestamp: timestamp ? new Date(timestamp).getTime() : Date.now(),\n CloudWatchMetrics:\n metricNames.length > 0\n ? [\n {\n Namespace: this.emfNamespace,\n Dimensions: [['level']],\n Metrics: metricNames.map((n) => ({ Name: n, Unit: 'None' })),\n },\n ]\n : [],\n };\n return stringifyForLog(fields);\n }\n\n private async putLogEvents(events: CwLogEvent[]): Promise<void> {\n await this.ensureStream();\n const logEvents = [...events].sort((a, b) => a.timestamp - b.timestamp);\n try {\n await this.call('PutLogEvents', {\n logGroupName: this.logGroupName,\n logStreamName: this.logStreamName,\n logEvents,\n });\n } catch (err) {\n const type = awsErrorType(err);\n if (type === 'DataAlreadyAcceptedException') return;\n if (type === 'ResourceNotFoundException') this.streamReady = false;\n if (type === 'ExpiredTokenException') this.credentials.invalidate();\n throw err;\n }\n }\n\n private async ensureStream(): Promise<void> {\n if (this.streamReady) return;\n try {\n await this.call('CreateLogGroup', { logGroupName: this.logGroupName });\n } catch (err) {\n if (awsErrorType(err) === 'ExpiredTokenException') this.credentials.invalidate();\n if (!(err instanceof HttpError)) throw err;\n if (awsErrorType(err) !== 'ResourceAlreadyExistsException') {\n internalWarn(`CloudWatchTransport: CreateLogGroup failed, continuing (${err.message})`);\n }\n }\n try {\n await this.call('CreateLogStream', {\n logGroupName: this.logGroupName,\n logStreamName: this.logStreamName,\n });\n } catch (err) {\n if (awsErrorType(err) !== 'ResourceAlreadyExistsException') throw err;\n }\n this.streamReady = true;\n }\n\n private async call(action: string, payload: Record<string, unknown>): Promise<void> {\n const credentials = await this.credentials.get();\n const body = stringifyForLog(payload);\n const { host } = this.endpoint;\n const headers = signV4({\n method: 'POST',\n path: '/',\n headers: {\n host,\n 'content-type': 'application/x-amz-json-1.1',\n 'x-amz-target': `Logs_20140328.${action}`,\n },\n body,\n region: this.region,\n service: 'logs',\n credentials,\n });\n await httpRequest({\n url: this.endpoint,\n headers,\n body,\n timeoutMs: this.requestTimeoutMs,\n label: `CloudWatch ${action}`,\n secrets: () => [\n ...this.credentials.secretValues(),\n headers['authorization'],\n headers['x-amz-security-token'],\n ...urlSecrets(this.endpoint),\n ],\n });\n }\n}\n"],"mappings":"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"}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
const require_secret_config = require("./secret-config-
|
|
2
|
-
const require_internal_log = require("./internal-log-
|
|
3
|
-
const require_safe_stringify = require("./safe-stringify-
|
|
4
|
-
const require_entry_fields = require("./entry-fields-
|
|
5
|
-
const require_batch_buffer = require("./batch-buffer-
|
|
1
|
+
const require_secret_config = require("./secret-config-BvFl2dC8.js");
|
|
2
|
+
const require_internal_log = require("./internal-log-DwqTjhpb.js");
|
|
3
|
+
const require_safe_stringify = require("./safe-stringify-CN7icp8S.js");
|
|
4
|
+
const require_entry_fields = require("./entry-fields-CVwoQplO.js");
|
|
5
|
+
const require_batch_buffer = require("./batch-buffer-CFzKnuNZ.js");
|
|
6
6
|
let node_crypto = require("node:crypto");
|
|
7
7
|
node_crypto = require_secret_config.__toESM(node_crypto);
|
|
8
8
|
let node_os = require("node:os");
|
|
@@ -399,4 +399,4 @@ Object.defineProperty(exports, "CloudWatchTransport", {
|
|
|
399
399
|
}
|
|
400
400
|
});
|
|
401
401
|
|
|
402
|
-
//# sourceMappingURL=cloudwatch.transport-
|
|
402
|
+
//# sourceMappingURL=cloudwatch.transport-D4G5xYfG.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cloudwatch.transport-D4G5xYfG.js","names":["path","os","fs","httpRequest","crypto","HttpError","BatchBuffer","urlSecrets","isPermanentHttpError","stringifyForLog","mergeCoreFields","httpRequest"],"sources":["../src/transports/aws-credentials.ts","../src/transports/aws-sigv4.ts","../src/transports/cloudwatch.transport.ts"],"sourcesContent":["/**\n * AWS credential resolution without the SDK.\n *\n * Order: explicit config, environment variables, shared credentials file,\n * ECS/container credentials, EC2 instance metadata (IMDSv2).\n * Not supported: SSO, assume-role profiles, credential_process, web identity.\n */\n\nimport * as fs from 'node:fs';\nimport * as os from 'node:os';\nimport * as path from 'node:path';\n\nimport { internalWarn } from '../utils/internal-log';\nimport { type AwsCredentials } from './aws-sigv4';\nimport { httpRequest } from './batch-buffer';\nimport { protectSecrets } from './secret-config';\n\nconst REFRESH_MARGIN_MS = 5 * 60 * 1000;\nconst FAILURE_BACKOFF_MS = 30 * 1000;\nconst METADATA_TIMEOUT_MS = 2000;\n\nexport interface AwsCredentialConfig {\n accessKeyId?: string | undefined;\n secretAccessKey?: string | undefined;\n sessionToken?: string | undefined;\n}\n\n/** Parse the sections of an AWS ini file into `{ section: { key: value } }`. */\nexport function parseIni(text: string): Record<string, Record<string, string>> {\n const out: Record<string, Record<string, string>> = {};\n let section: Record<string, string> | undefined;\n for (const raw of text.split(/\\r?\\n/)) {\n const line = raw.trim();\n if (!line || line.startsWith('#') || line.startsWith(';')) continue;\n const header = /^\\[(.+)\\]$/.exec(line);\n if (header) {\n section = out[header[1]!.trim()] = out[header[1]!.trim()] ?? {};\n continue;\n }\n const eq = line.indexOf('=');\n if (eq > 0 && section) section[line.slice(0, eq).trim()] = line.slice(eq + 1).trim();\n }\n return out;\n}\n\nfunction fromEnv(): AwsCredentials | undefined {\n const accessKeyId = process.env['AWS_ACCESS_KEY_ID'];\n const secretAccessKey = process.env['AWS_SECRET_ACCESS_KEY'];\n if (!accessKeyId || !secretAccessKey) return undefined;\n return { accessKeyId, secretAccessKey, sessionToken: process.env['AWS_SESSION_TOKEN'] };\n}\n\nfunction fromSharedFile(): AwsCredentials | undefined {\n const file =\n process.env['AWS_SHARED_CREDENTIALS_FILE'] ?? path.join(os.homedir(), '.aws', 'credentials');\n const profile = process.env['AWS_PROFILE'] ?? 'default';\n let text: string;\n try {\n text = fs.readFileSync(file, 'utf8');\n } catch {\n return undefined;\n }\n const section = parseIni(text)[profile];\n const accessKeyId = section?.['aws_access_key_id'];\n const secretAccessKey = section?.['aws_secret_access_key'];\n if (!accessKeyId || !secretAccessKey) return undefined;\n return { accessKeyId, secretAccessKey, sessionToken: section?.['aws_session_token'] };\n}\n\ninterface CredentialDocument {\n AccessKeyId?: string;\n SecretAccessKey?: string;\n Token?: string;\n Expiration?: string;\n}\n\nfunction fromDocument(raw: string): AwsCredentials | undefined {\n const doc = JSON.parse(raw) as CredentialDocument;\n if (!doc.AccessKeyId || !doc.SecretAccessKey) return undefined;\n const expiresAt = doc.Expiration ? Date.parse(doc.Expiration) : Number.NaN;\n return {\n accessKeyId: doc.AccessKeyId,\n secretAccessKey: doc.SecretAccessKey,\n sessionToken: doc.Token,\n expiresAt: Number.isNaN(expiresAt) ? undefined : expiresAt,\n };\n}\n\nconst CONTAINER_HOSTS = new Set([\n // eslint-disable-next-line sonarjs/no-hardcoded-ip -- fixed ECS credentials endpoint\n '169.254.170.2',\n // eslint-disable-next-line sonarjs/no-hardcoded-ip -- fixed EKS pod identity endpoint\n '169.254.170.23',\n '[fd00:ec2::23]',\n 'localhost',\n '[::1]',\n]);\n\n/** Same rule as the AWS SDKs: never send the container token to an arbitrary http host. */\nfunction isAllowedContainerHost(url: URL): boolean {\n if (url.protocol === 'https:') return true;\n if (url.protocol !== 'http:') return false;\n return CONTAINER_HOSTS.has(url.hostname) || /^127(?:\\.\\d{1,3}){3}$/.test(url.hostname);\n}\n\nasync function fromContainer(): Promise<AwsCredentials | undefined> {\n const relative = process.env['AWS_CONTAINER_CREDENTIALS_RELATIVE_URI'];\n const full = process.env['AWS_CONTAINER_CREDENTIALS_FULL_URI'];\n if (!relative && !full) return undefined;\n const url = new URL(relative ? `http://169.254.170.2${relative}` : (full as string));\n if (!relative && !isAllowedContainerHost(url)) {\n internalWarn(\n `ignoring AWS_CONTAINER_CREDENTIALS_FULL_URI: ${url.host} is not https or a loopback / ECS / EKS address`\n );\n return undefined;\n }\n const headers: Record<string, string> = {};\n const tokenFile = process.env['AWS_CONTAINER_AUTHORIZATION_TOKEN_FILE'];\n const token = tokenFile\n ? fs.readFileSync(tokenFile, 'utf8').trim()\n : process.env['AWS_CONTAINER_AUTHORIZATION_TOKEN'];\n if (token) headers['Authorization'] = token;\n const res = await httpRequest({\n url,\n method: 'GET',\n headers,\n timeoutMs: METADATA_TIMEOUT_MS,\n label: 'AWS container credentials',\n });\n return fromDocument(res.body);\n}\n\nasync function fromInstanceMetadata(): Promise<AwsCredentials | undefined> {\n if (process.env['AWS_EC2_METADATA_DISABLED'] === 'true') return undefined;\n const base = process.env['AWS_EC2_METADATA_SERVICE_ENDPOINT'] ?? 'http://169.254.169.254';\n const get = (p: string, method: string, headers: Record<string, string>) =>\n httpRequest({\n url: new URL(p, base),\n method,\n headers,\n timeoutMs: METADATA_TIMEOUT_MS,\n label: 'EC2 instance metadata',\n });\n const session = await get('/latest/api/token', 'PUT', {\n 'X-aws-ec2-metadata-token-ttl-seconds': '21600',\n });\n const auth = { 'X-aws-ec2-metadata-token': session.body.trim() };\n const roles = await get('/latest/meta-data/iam/security-credentials/', 'GET', auth);\n const role = roles.body.split('\\n')[0]?.trim();\n if (!role) return undefined;\n const creds = await get(\n `/latest/meta-data/iam/security-credentials/${encodeURIComponent(role)}`,\n 'GET',\n auth\n );\n return fromDocument(creds.body);\n}\n\nexport class AwsCredentialProvider {\n private cached: AwsCredentials | undefined;\n private failedAt = 0;\n private readonly explicit: AwsCredentials | undefined;\n\n constructor(config: AwsCredentialConfig) {\n protectSecrets(this, ['cached', 'explicit']);\n if (config.accessKeyId && config.secretAccessKey) {\n this.explicit = {\n accessKeyId: config.accessKeyId,\n secretAccessKey: config.secretAccessKey,\n sessionToken: config.sessionToken,\n };\n }\n }\n\n /** Throws when no source yields credentials, so the caller keeps its buffer. */\n async get(): Promise<AwsCredentials> {\n if (this.explicit) return this.explicit;\n const env = fromEnv();\n if (env) return env;\n if (this.cached && !this.isExpiring(this.cached)) return this.cached;\n if (Date.now() - this.failedAt < FAILURE_BACKOFF_MS) {\n throw new Error('no AWS credentials found (retrying shortly)');\n }\n\n let found = fromSharedFile();\n for (const source of [fromContainer, fromInstanceMetadata]) {\n if (found) break;\n try {\n found = await source();\n } catch {\n /* source not available here; try the next */\n }\n }\n if (!found) {\n this.failedAt = Date.now();\n throw new Error(\n 'no AWS credentials found: set AWS_ACCESS_KEY_ID/AWS_SECRET_ACCESS_KEY, a shared credentials file, container credentials, or run on EC2 with an instance role'\n );\n }\n this.cached = found;\n return found;\n }\n\n /** Secret values this provider may hold, for scrubbing error text. */\n secretValues(): (string | undefined)[] {\n const env = process.env;\n return [\n this.explicit?.secretAccessKey,\n this.explicit?.sessionToken,\n this.cached?.secretAccessKey,\n this.cached?.sessionToken,\n env['AWS_SECRET_ACCESS_KEY'],\n env['AWS_SESSION_TOKEN'],\n ];\n }\n\n invalidate(): void {\n this.cached = undefined;\n this.failedAt = 0;\n }\n\n private isExpiring(c: AwsCredentials): boolean {\n return c.expiresAt !== undefined && c.expiresAt - Date.now() < REFRESH_MARGIN_MS;\n }\n}\n","/**\n * AWS Signature Version 4 request signing, dependency-free.\n */\n\nimport * as crypto from 'node:crypto';\n\nexport interface AwsCredentials {\n accessKeyId: string;\n secretAccessKey: string;\n sessionToken?: string | undefined;\n /** Epoch ms after which the credentials are no longer valid. */\n expiresAt?: number | undefined;\n}\n\nexport interface SignV4Options {\n method: string;\n path: string;\n query?: string;\n /** Must include `host`. Names are lowercased before signing. */\n headers: Record<string, string>;\n body: string;\n region: string;\n service: string;\n credentials: AwsCredentials;\n date?: Date;\n}\n\nconst sha256Hex = (data: string): string => crypto.createHash('sha256').update(data).digest('hex');\n\nconst hmac = (key: Buffer | string, msg: string): Buffer =>\n crypto.createHmac('sha256', key).update(msg).digest();\n\n/** Returns the request headers (lowercase names) with `x-amz-date` and `authorization` added. */\nexport function signV4(opts: SignV4Options): Record<string, string> {\n const {\n method,\n path,\n query = '',\n body,\n region,\n service,\n credentials,\n headers: input,\n date,\n } = opts;\n const amzDate = (date ?? new Date()).toISOString().replace(/[:-]|\\.\\d{3}/g, '');\n const dateStamp = amzDate.slice(0, 8);\n\n const headers: Record<string, string> = {};\n for (const [k, v] of Object.entries(input)) headers[k.toLowerCase()] = v;\n headers['x-amz-date'] = amzDate;\n if (credentials.sessionToken) headers['x-amz-security-token'] = credentials.sessionToken;\n\n const names = Object.keys(headers).sort();\n const canonicalHeaders = names\n .map((n) => `${n}:${headers[n]!.trim().replace(/\\s+/g, ' ')}\\n`)\n .join('');\n const signedHeaders = names.join(';');\n\n const canonicalRequest = [\n method,\n path,\n query,\n canonicalHeaders,\n signedHeaders,\n sha256Hex(body),\n ].join('\\n');\n const scope = `${dateStamp}/${region}/${service}/aws4_request`;\n const stringToSign = ['AWS4-HMAC-SHA256', amzDate, scope, sha256Hex(canonicalRequest)].join('\\n');\n\n const signingKey = hmac(\n hmac(hmac(hmac(`AWS4${credentials.secretAccessKey}`, dateStamp), region), service),\n 'aws4_request'\n );\n const signature = crypto.createHmac('sha256', signingKey).update(stringToSign).digest('hex');\n\n headers['authorization'] =\n `AWS4-HMAC-SHA256 Credential=${credentials.accessKeyId}/${scope}, ` +\n `SignedHeaders=${signedHeaders}, Signature=${signature}`;\n return headers;\n}\n","/**\n * logixia — AWS CloudWatch Logs transport\n *\n * Sends log entries to AWS CloudWatch Logs via the PutLogEvents API.\n * Supports EMF (Embedded Metric Format) for automatic metric extraction.\n *\n * Auth, in order: explicit config, environment variables, the shared\n * credentials file (AWS_PROFILE, AWS_SHARED_CREDENTIALS_FILE), ECS container\n * credentials, then EC2 instance metadata (IMDSv2). SSO, assume-role profiles\n * and credential_process are not supported. No SDK dependency — raw HTTPS with\n * AWS Signature Version 4.\n *\n * The log group and stream are created on first use if they do not exist.\n *\n * @example\n * ```ts\n * import { createLogger } from 'logixia';\n * import { CloudWatchTransport } from 'logixia/cloudwatch';\n *\n * const logger = createLogger({\n * transports: {\n * custom: [\n * new CloudWatchTransport({\n * region: 'us-east-1',\n * logGroupName: '/myapp/production',\n * logStreamName: `api-${process.env.HOSTNAME}`,\n * batchSize: 100,\n * flushIntervalMs: 5000,\n * }),\n * ],\n * },\n * });\n * ```\n */\n\nimport type { IAsyncTransport, TransportLogEntry } from '../types/transport.types';\nimport { internalWarn } from '../utils/internal-log';\nimport { stringifyForLog } from '../utils/safe-stringify';\nimport { AwsCredentialProvider } from './aws-credentials';\nimport { signV4 } from './aws-sigv4';\nimport {\n BatchBuffer,\n DEFAULT_MAX_BUFFER_SIZE,\n DEFAULT_REQUEST_TIMEOUT_MS,\n HttpError,\n httpRequest,\n isPermanentHttpError,\n} from './batch-buffer';\nimport { mergeCoreFields } from './entry-fields';\nimport { protectSecrets, urlSecrets } from './secret-config';\n\nexport interface CloudWatchTransportConfig {\n /** AWS region, e.g. `'us-east-1'`. Falls back to `AWS_REGION` env var. */\n region?: string;\n /** CloudWatch Logs group name. Created automatically if it does not exist. */\n logGroupName: string;\n /** CloudWatch Logs stream name. Defaults to hostname + process PID. */\n logStreamName?: string;\n /** Override the Logs endpoint, e.g. for LocalStack. Default: `https://logs.<region>.amazonaws.com`. */\n endpoint?: string;\n /** AWS access key ID. Falls back to the credential chain described above. */\n accessKeyId?: string;\n /** AWS secret access key. Used together with `accessKeyId`. */\n secretAccessKey?: string;\n /** AWS session token for temporary credentials. Used together with `accessKeyId`. */\n sessionToken?: string;\n /**\n * Number of log events to batch before flushing.\n * CloudWatch allows max 10,000 events per PutLogEvents call; larger values are capped.\n * @default 100\n */\n batchSize?: number;\n /**\n * Max ms between flushes even if batchSize is not reached.\n * @default 5000\n */\n flushIntervalMs?: number;\n /**\n * Enable EMF (Embedded Metric Format) — wraps log entries as CloudWatch\n * metric namespaces so numeric fields become CloudWatch Metrics automatically.\n * @default false\n */\n emf?: boolean;\n /** CloudWatch Metrics namespace used by EMF. @default 'Logixia' */\n emfNamespace?: string;\n /**\n * Payload fields published as EMF metrics. When set, only these numeric\n * fields become metrics; when unset every numeric payload field does (up to\n * the EMF limit of 100 per entry).\n */\n emfMetrics?: string[];\n /** Abort a request that has not finished after this many ms. @default 10000 */\n requestTimeoutMs?: number;\n /** Max buffered events; the oldest are dropped past this. @default 10000 */\n maxBufferSize?: number;\n /** Minimum log level to forward. */\n level?: string;\n}\n\nconst MAX_EVENTS_PER_PUT = 10_000;\nconst EMF_MAX_METRICS = 100;\n\n/** Error types worth retrying even though CloudWatch reports them as HTTP 400. */\nconst RETRYABLE_TYPES = new Set([\n 'ThrottlingException',\n 'ThrottledException',\n 'LimitExceededException',\n 'ServiceUnavailableException',\n 'ExpiredTokenException',\n 'ResourceNotFoundException',\n]);\n\nfunction awsErrorType(err: unknown): string | undefined {\n if (!(err instanceof HttpError)) return undefined;\n try {\n const type = (JSON.parse(err.body) as { __type?: string }).__type;\n return type?.split('#').pop();\n } catch {\n return undefined;\n }\n}\n\ninterface CwLogEvent {\n timestamp: number;\n message: string;\n}\n\n/**\n * AWS CloudWatch Logs transport with EMF support and batched PutLogEvents calls.\n */\nexport class CloudWatchTransport implements IAsyncTransport {\n public readonly name = 'cloudwatch';\n public readonly batchSize: number;\n public readonly flushInterval: number;\n public readonly level: string | undefined;\n\n private readonly buffer: BatchBuffer<CwLogEvent>;\n private readonly requestTimeoutMs: number;\n private flushTimer: NodeJS.Timeout | null = null;\n private readonly credentials: AwsCredentialProvider;\n private readonly endpoint: URL;\n private streamReady = false;\n\n private readonly region: string;\n private readonly logGroupName: string;\n private readonly logStreamName: string;\n private readonly emf: boolean;\n private readonly emfNamespace: string;\n private readonly emfMetrics: ReadonlySet<string> | undefined;\n\n constructor(config: CloudWatchTransportConfig) {\n this.region =\n config.region ??\n process.env['AWS_REGION'] ??\n process.env['AWS_DEFAULT_REGION'] ??\n 'us-east-1';\n this.logGroupName = config.logGroupName;\n this.logStreamName =\n config.logStreamName ?? `${process.env['HOSTNAME'] ?? 'node'}-${process.pid}`;\n this.credentials = new AwsCredentialProvider(config);\n this.endpoint = new URL(config.endpoint ?? `https://logs.${this.region}.amazonaws.com`);\n this.batchSize = Math.min(config.batchSize ?? 100, MAX_EVENTS_PER_PUT);\n this.emfNamespace = config.emfNamespace ?? 'Logixia';\n this.flushInterval = config.flushIntervalMs ?? 5000;\n this.emf = config.emf ?? false;\n this.emfMetrics = config.emfMetrics ? new Set(config.emfMetrics) : undefined;\n this.level = config.level;\n this.requestTimeoutMs = config.requestTimeoutMs ?? DEFAULT_REQUEST_TIMEOUT_MS;\n this.buffer = new BatchBuffer<CwLogEvent>({\n name: 'CloudWatchTransport',\n batchSize: this.batchSize,\n maxBufferSize: config.maxBufferSize ?? DEFAULT_MAX_BUFFER_SIZE,\n send: (events) => this.putLogEvents(events),\n secrets: () => [...this.credentials.secretValues(), ...urlSecrets(this.endpoint)],\n shouldRetry: (err) =>\n !isPermanentHttpError(err) || RETRYABLE_TYPES.has(awsErrorType(err) ?? ''),\n });\n\n this.flushTimer = setInterval(() => {\n this.flush().catch(() => {});\n }, this.flushInterval);\n if (this.flushTimer.unref) this.flushTimer.unref();\n protectSecrets(this, ['credentials', 'endpoint']);\n }\n\n write(entry: TransportLogEntry): void {\n const timestamp = entry.timestamp ? new Date(entry.timestamp).getTime() : Date.now();\n const message = this.emf ? this.toEmf(entry) : stringifyForLog(entry);\n this.buffer.push({ timestamp, message });\n this.buffer.flushIfFull();\n }\n\n flush(): Promise<void> {\n return this.buffer.flush();\n }\n\n /**\n * Flush remaining events and stop the interval timer on shutdown. Without this\n * the manager's close() skips the transport (close was undefined) and any\n * buffered events were lost on deploy. Waits for any in-flight send first.\n */\n async close(): Promise<void> {\n if (this.flushTimer) {\n clearInterval(this.flushTimer);\n this.flushTimer = null;\n }\n await this.buffer.close();\n }\n\n private toEmf(entry: TransportLogEntry): string {\n const { level, message, data: payload, timestamp } = entry;\n const fields = mergeCoreFields({ _aws: undefined, level, message }, payload);\n const metricNames: string[] = [];\n for (const [k, v] of Object.entries(fields)) {\n if (k === '_aws' || k === 'level' || k === 'message' || typeof v !== 'number') continue;\n if (this.emfMetrics && !this.emfMetrics.has(k)) continue;\n if (metricNames.length < EMF_MAX_METRICS) metricNames.push(k);\n }\n fields['_aws'] = {\n Timestamp: timestamp ? new Date(timestamp).getTime() : Date.now(),\n CloudWatchMetrics:\n metricNames.length > 0\n ? [\n {\n Namespace: this.emfNamespace,\n Dimensions: [['level']],\n Metrics: metricNames.map((n) => ({ Name: n, Unit: 'None' })),\n },\n ]\n : [],\n };\n return stringifyForLog(fields);\n }\n\n private async putLogEvents(events: CwLogEvent[]): Promise<void> {\n await this.ensureStream();\n const logEvents = [...events].sort((a, b) => a.timestamp - b.timestamp);\n try {\n await this.call('PutLogEvents', {\n logGroupName: this.logGroupName,\n logStreamName: this.logStreamName,\n logEvents,\n });\n } catch (err) {\n const type = awsErrorType(err);\n if (type === 'DataAlreadyAcceptedException') return;\n if (type === 'ResourceNotFoundException') this.streamReady = false;\n if (type === 'ExpiredTokenException') this.credentials.invalidate();\n throw err;\n }\n }\n\n private async ensureStream(): Promise<void> {\n if (this.streamReady) return;\n try {\n await this.call('CreateLogGroup', { logGroupName: this.logGroupName });\n } catch (err) {\n if (awsErrorType(err) === 'ExpiredTokenException') this.credentials.invalidate();\n if (!(err instanceof HttpError)) throw err;\n if (awsErrorType(err) !== 'ResourceAlreadyExistsException') {\n internalWarn(`CloudWatchTransport: CreateLogGroup failed, continuing (${err.message})`);\n }\n }\n try {\n await this.call('CreateLogStream', {\n logGroupName: this.logGroupName,\n logStreamName: this.logStreamName,\n });\n } catch (err) {\n if (awsErrorType(err) !== 'ResourceAlreadyExistsException') throw err;\n }\n this.streamReady = true;\n }\n\n private async call(action: string, payload: Record<string, unknown>): Promise<void> {\n const credentials = await this.credentials.get();\n const body = stringifyForLog(payload);\n const { host } = this.endpoint;\n const headers = signV4({\n method: 'POST',\n path: '/',\n headers: {\n host,\n 'content-type': 'application/x-amz-json-1.1',\n 'x-amz-target': `Logs_20140328.${action}`,\n },\n body,\n region: this.region,\n service: 'logs',\n credentials,\n });\n await httpRequest({\n url: this.endpoint,\n headers,\n body,\n timeoutMs: this.requestTimeoutMs,\n label: `CloudWatch ${action}`,\n secrets: () => [\n ...this.credentials.secretValues(),\n headers['authorization'],\n headers['x-amz-security-token'],\n ...urlSecrets(this.endpoint),\n ],\n });\n }\n}\n"],"mappings":"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"}
|