h1v3 0.7.3 → 0.7.4
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.
|
@@ -26,7 +26,8 @@ export async function inject({ database, authentication, metaURL, handleError =
|
|
|
26
26
|
if (!metaURL) throw new Error("Missing metaURL");
|
|
27
27
|
if (!authentication) throw new Error("Missing authentication");
|
|
28
28
|
|
|
29
|
-
const meta = await fetch(metaURL).then(resp => resp.json())
|
|
29
|
+
// const meta = await fetch(metaURL).then(resp => resp.json())
|
|
30
|
+
const { default: meta } = await import(metaURL, { with: { type: "json" } });
|
|
30
31
|
|
|
31
32
|
const log = logger(database, authentication, meta.o11y.path);
|
|
32
33
|
const teamMembershipStoreFactory = ({ tid }) => eventStore(database, authentication, populateParameters({ tid }, meta.team.membership.path));
|
|
@@ -14,25 +14,35 @@ function munge(attributes) {
|
|
|
14
14
|
export function logger(database, authentication, path, defaultAttributes) {
|
|
15
15
|
|
|
16
16
|
const { db, ref, set } = database;
|
|
17
|
+
const { auth } = authentication;
|
|
17
18
|
|
|
18
|
-
async function recordLog(
|
|
19
|
-
|
|
20
|
-
const span_id = generateSpanId();
|
|
21
|
-
console.log(defaultAttributes, sharedAttributes, attributes);
|
|
22
|
-
const data = {
|
|
23
|
-
meta: { uid: authentication.auth.currentUser.uid },
|
|
24
|
-
body,
|
|
25
|
-
trace_id,
|
|
26
|
-
span_id,
|
|
27
|
-
severity_text: level,
|
|
28
|
-
time_client_ms: Date.now(),
|
|
29
|
-
attributes: munge({ ...defaultAttributes, ...sharedAttributes, ...attributes })
|
|
30
|
-
};
|
|
31
|
-
if (parent_id) data.parent_id = parent_id;
|
|
32
|
-
const refPath = path.replace("$id", timeId());
|
|
33
|
-
console.log("Logging", data, "to", refPath);
|
|
34
|
-
return await set(ref(db, refPath), data);
|
|
19
|
+
async function recordLog(traceId, level, sharedAttributes, { message, parentSpanId, spanId, attributes }) {
|
|
35
20
|
|
|
21
|
+
let data;
|
|
22
|
+
try {
|
|
23
|
+
|
|
24
|
+
const uid = auth?.currentUser?.uid;
|
|
25
|
+
if (!uid) throw new Error("No current user id. Is the user logged in?");
|
|
26
|
+
|
|
27
|
+
spanId = spanId || generateSpanId();
|
|
28
|
+
data = {
|
|
29
|
+
meta: { uid },
|
|
30
|
+
message,
|
|
31
|
+
traceId,
|
|
32
|
+
spanId,
|
|
33
|
+
severity_text: level,
|
|
34
|
+
time_client_ms: Date.now(),
|
|
35
|
+
attributes: munge({ ...defaultAttributes, ...sharedAttributes, ...attributes })
|
|
36
|
+
};
|
|
37
|
+
if (parentSpanId) data.parentSpanId = parentSpanId;
|
|
38
|
+
const refPath = path.replace("$id", `${traceId}-${spanId}`);
|
|
39
|
+
return await set(ref(db, refPath), data);
|
|
40
|
+
|
|
41
|
+
} catch(err) {
|
|
42
|
+
|
|
43
|
+
console.error("Error dispatching o11y message", data, err);
|
|
44
|
+
|
|
45
|
+
}
|
|
36
46
|
|
|
37
47
|
}
|
|
38
48
|
|
|
@@ -41,17 +51,13 @@ export function logger(database, authentication, path, defaultAttributes) {
|
|
|
41
51
|
context(sharedAttributes) {
|
|
42
52
|
|
|
43
53
|
const id = generateTraceId();
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
info: recordLog.bind(this, id, "INFO", sharedAttributes),
|
|
49
|
-
warn: recordLog.bind(this, id, "WARN", sharedAttributes),
|
|
50
|
-
error: recordLog.bind(this, id, "ERROR", sharedAttributes),
|
|
51
|
-
fatal: recordLog.bind(this, id, "FATAL", sharedAttributes)
|
|
52
|
-
};
|
|
54
|
+
const ret = { id };
|
|
55
|
+
for(const x of ["debug", "info", "notice", "warning", "error", "critical", "alert", "emergency"])
|
|
56
|
+
ret[x] = recordLog.bind(this, id, x.toUpperCase(), sharedAttributes);
|
|
57
|
+
return ret;
|
|
53
58
|
|
|
54
59
|
}
|
|
60
|
+
|
|
55
61
|
};
|
|
56
62
|
|
|
57
63
|
}
|
package/package.json
CHANGED
|
@@ -11,12 +11,15 @@ function decideSeverity(newData) {
|
|
|
11
11
|
return googleLogLevels.includes(text) ? text : "INFO";
|
|
12
12
|
|
|
13
13
|
}
|
|
14
|
+
const DISPATCHED = "DISPATCHED";
|
|
15
|
+
const BLOCKED = "BLOCKED";
|
|
16
|
+
|
|
14
17
|
/*
|
|
15
18
|
|
|
16
19
|
message, severity, // required
|
|
17
20
|
traceId, spanId, timestamp, // advised
|
|
18
21
|
logData, // optional log line
|
|
19
|
-
spanStart, spanEnd, spanAttributes // optional trace attributes
|
|
22
|
+
spanStart, spanEnd, spanAttributes, parentSpanId // optional trace attributes
|
|
20
23
|
|
|
21
24
|
*/
|
|
22
25
|
function handleO11yEventWritten(observe, e) {
|
|
@@ -26,24 +29,66 @@ function handleO11yEventWritten(observe, e) {
|
|
|
26
29
|
if (!newData.time_server_ms) {
|
|
27
30
|
|
|
28
31
|
const now = new Date();
|
|
29
|
-
const time_server_ms = now.valueOf();
|
|
30
32
|
const timestamp = now.toISOString();
|
|
31
|
-
const
|
|
33
|
+
const time_server_ms = now.valueOf();
|
|
34
|
+
const { traceId, spanId, parentSpanId, ...rest } = newData;
|
|
35
|
+
|
|
36
|
+
const { id } = e.params;
|
|
37
|
+
const [id_traceId, id_spanId] = id.split("-");
|
|
38
|
+
let action;
|
|
39
|
+
if (traceId !== id_traceId || spanId !== id_spanId) {
|
|
40
|
+
|
|
41
|
+
action = blockEvent({ message: "Mismatched event id", timestamp, details: { id, traceId, spanId }});
|
|
42
|
+
|
|
43
|
+
} else if (!newData?.meta?.uid) {
|
|
44
|
+
|
|
45
|
+
action = blockEvent({ message: "Missing / invalid uid", timestamp, details: { uid: newData?.meta?.uid } });
|
|
46
|
+
|
|
47
|
+
} else {
|
|
48
|
+
|
|
49
|
+
action = dispatch({ rest, time_server_ms, traceId, spanId, parentSpanId, timestamp });
|
|
50
|
+
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
after.ref.update({
|
|
54
|
+
time_server_ms,
|
|
55
|
+
timestamp,
|
|
56
|
+
action
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
}
|
|
32
60
|
|
|
33
|
-
const { traceId, spanId, ...rest } = newData;
|
|
34
|
-
const logData = { ...rest, time_server_ms };
|
|
35
61
|
|
|
62
|
+
function dispatch({ rest, time_server_ms, traceId, spanId, parentSpanId, timestamp }) {
|
|
63
|
+
|
|
64
|
+
const message = newData?.message || "Missing log message";
|
|
65
|
+
const uid = newData.meta?.uid;
|
|
66
|
+
const logData = { ...rest, time_server_ms };
|
|
36
67
|
observe({
|
|
37
68
|
message,
|
|
38
69
|
severity: decideSeverity(newData),
|
|
39
70
|
|
|
40
|
-
traceId
|
|
41
|
-
spanId
|
|
71
|
+
traceId,
|
|
72
|
+
spanId,
|
|
73
|
+
parentSpanId,
|
|
42
74
|
timestamp,
|
|
43
75
|
|
|
44
|
-
logData
|
|
76
|
+
logData,
|
|
77
|
+
spanAttributes: { "user.id": uid }
|
|
78
|
+
});
|
|
79
|
+
return DISPATCHED;
|
|
80
|
+
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
function blockEvent({ message, timestamp, details }) {
|
|
84
|
+
|
|
85
|
+
observe({
|
|
86
|
+
message: `O11y event blocked: ${message}`,
|
|
87
|
+
severity: "CRITICAL",
|
|
88
|
+
timestamp,
|
|
89
|
+
logData: { ...details, newData }
|
|
45
90
|
});
|
|
46
|
-
|
|
91
|
+
return BLOCKED;
|
|
47
92
|
|
|
48
93
|
}
|
|
49
94
|
|
|
@@ -73,29 +118,30 @@ export function configureO11yStore({ paths, onValueWritten, observe, region, ins
|
|
|
73
118
|
read: false,
|
|
74
119
|
write: all(
|
|
75
120
|
// required
|
|
76
|
-
assertNewDataHasString("
|
|
121
|
+
assertNewDataHasString("message", 500, 1),
|
|
77
122
|
assertNewDataHasOneOf("severity_text", ...googleLogLevels),
|
|
78
123
|
// trace context
|
|
79
124
|
all(
|
|
80
|
-
assertNewDataHasLowercaseHexCharacters("
|
|
81
|
-
assertNewDataFieldDoesNotMatch("
|
|
125
|
+
assertNewDataHasLowercaseHexCharacters("traceId", 32),
|
|
126
|
+
assertNewDataFieldDoesNotMatch("traceId", "0*")
|
|
82
127
|
),
|
|
83
128
|
all(
|
|
84
|
-
assertNewDataHasLowercaseHexCharacters("
|
|
85
|
-
assertNewDataFieldDoesNotMatch("
|
|
129
|
+
assertNewDataHasLowercaseHexCharacters("spanId", 16),
|
|
130
|
+
assertNewDataFieldDoesNotMatch("spanId", "0*")
|
|
86
131
|
),
|
|
87
|
-
// forbid server time faking
|
|
132
|
+
// forbid server time and action faking
|
|
88
133
|
assertNewDataDoesNotHave("time_server_ms"),
|
|
134
|
+
assertNewDataDoesNotHave("action"),
|
|
89
135
|
// optional bits
|
|
90
136
|
any(
|
|
91
137
|
assertNewDataDoesNotHave("time_client_ms"),
|
|
92
138
|
assertNewDataHasNumber("time_client_ms")
|
|
93
139
|
),
|
|
94
140
|
any(
|
|
95
|
-
assertNewDataDoesNotHave("
|
|
141
|
+
assertNewDataDoesNotHave("parentSpanId"),
|
|
96
142
|
all(
|
|
97
|
-
assertNewDataHasLowercaseHexCharacters("
|
|
98
|
-
assertNewDataFieldDoesNotMatch("
|
|
143
|
+
assertNewDataHasLowercaseHexCharacters("parentSpanId", 16),
|
|
144
|
+
assertNewDataFieldDoesNotMatch("parentSpanId", "0*")
|
|
99
145
|
)
|
|
100
146
|
)
|
|
101
147
|
)
|
|
@@ -9,7 +9,7 @@ export function provider({ trace, projectId, serviceName, log }) {
|
|
|
9
9
|
message, severity, // required
|
|
10
10
|
traceId, spanId, timestamp, // advised
|
|
11
11
|
logData, // optional log line
|
|
12
|
-
spanStart, spanEnd, spanAttributes // optional trace attributes
|
|
12
|
+
spanStart, spanEnd, spanAttributes, parentSpanId // optional trace attributes
|
|
13
13
|
}) => {
|
|
14
14
|
|
|
15
15
|
if (!message) throw new Error("Missing message");
|
|
@@ -30,7 +30,7 @@ export function provider({ trace, projectId, serviceName, log }) {
|
|
|
30
30
|
const startTime = asISOString(spanStart);
|
|
31
31
|
const endTime = asISOString(spanEnd);
|
|
32
32
|
|
|
33
|
-
await createSpan({ trace }, { serviceName, projectTraceSpanName, message, spanId, startTime, endTime, spanAttributes });
|
|
33
|
+
await createSpan({ trace }, { parentSpanId, serviceName, projectTraceSpanName, message, spanId, startTime, endTime, spanAttributes });
|
|
34
34
|
await writeLogLine({ log, projectId }, { tracePath, spanId, severity, timestamp, message, logData });
|
|
35
35
|
|
|
36
36
|
};
|
|
@@ -92,23 +92,25 @@ async function writeLogLine({ log, projectId }, { message, tracePath, spanId, se
|
|
|
92
92
|
|
|
93
93
|
}
|
|
94
94
|
|
|
95
|
-
async function createSpan({ trace }, { serviceName, projectTraceSpanName, spanId, startTime, endTime, spanAttributes, message }) {
|
|
95
|
+
async function createSpan({ trace }, { serviceName, projectTraceSpanName, spanId, parentSpanId, startTime, endTime, spanAttributes, message }) {
|
|
96
96
|
|
|
97
97
|
const attributes = toTraceAttributes({
|
|
98
98
|
"service.name": serviceName,
|
|
99
99
|
message,
|
|
100
100
|
...spanAttributes
|
|
101
101
|
});
|
|
102
|
+
const requestBody = {
|
|
103
|
+
attributes,
|
|
104
|
+
name: projectTraceSpanName,
|
|
105
|
+
spanId,
|
|
106
|
+
displayName: { value: serviceName },
|
|
107
|
+
startTime,
|
|
108
|
+
endTime
|
|
109
|
+
};
|
|
110
|
+
if (parentSpanId) requestBody.parentSpanId = parentSpanId;
|
|
102
111
|
await trace.projects.traces.spans.createSpan({
|
|
103
112
|
name: projectTraceSpanName,
|
|
104
|
-
requestBody
|
|
105
|
-
attributes,
|
|
106
|
-
name: projectTraceSpanName,
|
|
107
|
-
spanId,
|
|
108
|
-
displayName: { value: serviceName },
|
|
109
|
-
startTime,
|
|
110
|
-
endTime
|
|
111
|
-
}
|
|
113
|
+
requestBody
|
|
112
114
|
});
|
|
113
115
|
|
|
114
116
|
}
|
package/src/system/main.js
CHANGED