@teamkeel/functions-runtime 0.313.7 → 0.314.0
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/package.json +3 -1
- package/pnpm-lock.yaml +319 -530
- package/src/ModelAPI.js +42 -8
- package/src/QueryBuilder.js +7 -1
- package/src/tracing.js +30 -0
- package/src/tracing.test.js +56 -0
package/src/ModelAPI.js
CHANGED
|
@@ -4,6 +4,7 @@ const { QueryContext } = require("./QueryContext");
|
|
|
4
4
|
const { applyWhereConditions } = require("./applyWhereConditions");
|
|
5
5
|
const { applyJoins } = require("./applyJoins");
|
|
6
6
|
const { camelCaseObject, snakeCaseObject } = require("./casing");
|
|
7
|
+
const tracing = require("./tracing");
|
|
7
8
|
|
|
8
9
|
/**
|
|
9
10
|
* RelationshipConfig is a simple representation of a model field that
|
|
@@ -48,7 +49,7 @@ class ModelAPI {
|
|
|
48
49
|
async create(values) {
|
|
49
50
|
try {
|
|
50
51
|
const defaults = this._defaultValues();
|
|
51
|
-
const
|
|
52
|
+
const query = this._db
|
|
52
53
|
.insertInto(this._tableName)
|
|
53
54
|
.values(
|
|
54
55
|
snakeCaseObject({
|
|
@@ -56,8 +57,15 @@ class ModelAPI {
|
|
|
56
57
|
...values,
|
|
57
58
|
})
|
|
58
59
|
)
|
|
59
|
-
.returningAll()
|
|
60
|
-
|
|
60
|
+
.returningAll();
|
|
61
|
+
const sql = query.compile().sql;
|
|
62
|
+
const row = await tracing.withSpan(
|
|
63
|
+
`${this._tableName}.create`,
|
|
64
|
+
(span) => {
|
|
65
|
+
span.setAttribute("sql", sql);
|
|
66
|
+
return query.executeTakeFirstOrThrow();
|
|
67
|
+
}
|
|
68
|
+
);
|
|
61
69
|
|
|
62
70
|
return camelCaseObject(row);
|
|
63
71
|
} catch (e) {
|
|
@@ -76,7 +84,11 @@ class ModelAPI {
|
|
|
76
84
|
builder = applyJoins(context, builder, where);
|
|
77
85
|
builder = applyWhereConditions(context, builder, where);
|
|
78
86
|
|
|
79
|
-
const
|
|
87
|
+
const sql = builder.compile().sql;
|
|
88
|
+
const row = await tracing.withSpan(`${this._tableName}.findOne`, (span) => {
|
|
89
|
+
span.setAttribute("sql", sql);
|
|
90
|
+
return builder.executeTakeFirst();
|
|
91
|
+
});
|
|
80
92
|
if (!row) {
|
|
81
93
|
return null;
|
|
82
94
|
}
|
|
@@ -94,8 +106,16 @@ class ModelAPI {
|
|
|
94
106
|
|
|
95
107
|
builder = applyJoins(context, builder, where);
|
|
96
108
|
builder = applyWhereConditions(context, builder, where);
|
|
97
|
-
|
|
98
|
-
|
|
109
|
+
const query = builder.orderBy("id");
|
|
110
|
+
|
|
111
|
+
const sql = query.compile().sql;
|
|
112
|
+
const rows = await tracing.withSpan(
|
|
113
|
+
`${this._tableName}.findMany`,
|
|
114
|
+
(span) => {
|
|
115
|
+
span.setAttribute("sql", sql);
|
|
116
|
+
return builder.execute();
|
|
117
|
+
}
|
|
118
|
+
);
|
|
99
119
|
return rows.map((x) => camelCaseObject(x));
|
|
100
120
|
}
|
|
101
121
|
|
|
@@ -110,7 +130,14 @@ class ModelAPI {
|
|
|
110
130
|
builder = applyWhereConditions(context, builder, where);
|
|
111
131
|
|
|
112
132
|
try {
|
|
113
|
-
const
|
|
133
|
+
const sql = builder.compile().sql;
|
|
134
|
+
const row = await tracing.withSpan(
|
|
135
|
+
`${this._tableName}.update`,
|
|
136
|
+
(span) => {
|
|
137
|
+
span.setAttribute("sql", sql);
|
|
138
|
+
return builder.executeTakeFirstOrThrow();
|
|
139
|
+
}
|
|
140
|
+
);
|
|
114
141
|
|
|
115
142
|
return camelCaseObject(row);
|
|
116
143
|
} catch (e) {
|
|
@@ -127,7 +154,14 @@ class ModelAPI {
|
|
|
127
154
|
builder = applyWhereConditions(context, builder, where);
|
|
128
155
|
|
|
129
156
|
try {
|
|
130
|
-
const
|
|
157
|
+
const sql = builder.compile().sql;
|
|
158
|
+
const row = await tracing.withSpan(
|
|
159
|
+
`${this._tableName}.delete`,
|
|
160
|
+
(span) => {
|
|
161
|
+
span.setAttribute("sql", sql);
|
|
162
|
+
return builder.executeTakeFirstOrThrow();
|
|
163
|
+
}
|
|
164
|
+
);
|
|
131
165
|
|
|
132
166
|
return row.id;
|
|
133
167
|
} catch (e) {
|
package/src/QueryBuilder.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
const { applyWhereConditions } = require("./applyWhereConditions");
|
|
2
2
|
const { applyJoins } = require("./applyJoins");
|
|
3
3
|
const { camelCaseObject } = require("./casing");
|
|
4
|
+
const tracing = require("./tracing");
|
|
4
5
|
|
|
5
6
|
class QueryBuilder {
|
|
6
7
|
/**
|
|
@@ -34,7 +35,12 @@ class QueryBuilder {
|
|
|
34
35
|
}
|
|
35
36
|
|
|
36
37
|
async findMany() {
|
|
37
|
-
const
|
|
38
|
+
const query = this._db.orderBy("id");
|
|
39
|
+
const sql = query.compile().sql;
|
|
40
|
+
const rows = await tracing.withSpan(`query`, (span) => {
|
|
41
|
+
span.setAttribute("sql", sql);
|
|
42
|
+
return query.execute();
|
|
43
|
+
});
|
|
38
44
|
return rows.map((x) => camelCaseObject(x));
|
|
39
45
|
}
|
|
40
46
|
}
|
package/src/tracing.js
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
const opentelemetry = require("@opentelemetry/api");
|
|
2
|
+
|
|
3
|
+
const serviceName = "customerCustomFunctions";
|
|
4
|
+
|
|
5
|
+
const tracer = opentelemetry.trace.getTracer(serviceName);
|
|
6
|
+
|
|
7
|
+
function withSpan(name, fn) {
|
|
8
|
+
return tracer.startActiveSpan(name, async (span) => {
|
|
9
|
+
try {
|
|
10
|
+
// await the thing (this means we can use try/catch)
|
|
11
|
+
return await fn(span);
|
|
12
|
+
} catch (err) {
|
|
13
|
+
// record any errors
|
|
14
|
+
span.recordException(err);
|
|
15
|
+
span.setStatus({
|
|
16
|
+
code: opentelemetry.SpanStatusCode.ERROR,
|
|
17
|
+
message: err.message,
|
|
18
|
+
});
|
|
19
|
+
// re-throw the error
|
|
20
|
+
throw err;
|
|
21
|
+
} finally {
|
|
22
|
+
// make sure the span is ended
|
|
23
|
+
span.end();
|
|
24
|
+
}
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
module.exports = {
|
|
29
|
+
withSpan,
|
|
30
|
+
};
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { expect, test, beforeEach } from "vitest";
|
|
2
|
+
import tracing from "./tracing";
|
|
3
|
+
import { NodeTracerProvider, Span } from "@opentelemetry/sdk-trace-node";
|
|
4
|
+
|
|
5
|
+
let spanEvents = [];
|
|
6
|
+
const provider = new NodeTracerProvider({});
|
|
7
|
+
provider.addSpanProcessor({
|
|
8
|
+
forceFlush() {
|
|
9
|
+
return Promise.resolve();
|
|
10
|
+
},
|
|
11
|
+
onStart(span, parentContext) {
|
|
12
|
+
spanEvents.push({ event: "onStart", span, parentContext });
|
|
13
|
+
},
|
|
14
|
+
onEnd(span) {
|
|
15
|
+
spanEvents.push({ event: "onEnd", span });
|
|
16
|
+
},
|
|
17
|
+
shutdown() {
|
|
18
|
+
return Promise.resolve();
|
|
19
|
+
},
|
|
20
|
+
});
|
|
21
|
+
provider.register();
|
|
22
|
+
|
|
23
|
+
beforeEach(() => {
|
|
24
|
+
spanEvents = [];
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
test("withSpan span time", async () => {
|
|
28
|
+
const waitTimeMillis = 100;
|
|
29
|
+
await tracing.withSpan("name", async () => {
|
|
30
|
+
await new Promise((resolve) => setTimeout(resolve, waitTimeMillis));
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
expect(spanEvents.map((e) => e.event)).toEqual(["onStart", "onEnd"]);
|
|
34
|
+
const spanDuration = spanEvents.pop().span._duration.pop();
|
|
35
|
+
const waitTimeNanos = waitTimeMillis * 1000 * 1000;
|
|
36
|
+
expect(spanDuration).toBeGreaterThan(waitTimeNanos);
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
test("withSpan on error", async () => {
|
|
40
|
+
try {
|
|
41
|
+
await tracing.withSpan("name", async () => {
|
|
42
|
+
throw "err";
|
|
43
|
+
});
|
|
44
|
+
// previous line should have an error thrown
|
|
45
|
+
expect(true).toEqual(false);
|
|
46
|
+
} catch (e) {
|
|
47
|
+
expect(e).toEqual("err");
|
|
48
|
+
expect(spanEvents.map((e) => e.event)).toEqual(["onStart", "onEnd"]);
|
|
49
|
+
const lastSpanEvents = spanEvents.pop().span.events;
|
|
50
|
+
expect(lastSpanEvents).length(1);
|
|
51
|
+
expect(lastSpanEvents[0].name).toEqual("exception");
|
|
52
|
+
expect(lastSpanEvents[0].attributes).toEqual({
|
|
53
|
+
"exception.message": "err",
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
});
|