@oneuptime/common 11.5.13 → 11.6.1
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/Models/AnalyticsModels/AnalyticsBaseModel/AnalyticsBaseModel.ts +41 -24
- package/Models/AnalyticsModels/MetricBaselineHourly.ts +2 -0
- package/Models/AnalyticsModels/MetricItemAggMV1m.ts +5 -2
- package/Models/AnalyticsModels/MetricItemAggMV1mByContainer.ts +5 -2
- package/Models/AnalyticsModels/MetricItemAggMV1mByHostV2.ts +5 -2
- package/Models/AnalyticsModels/MetricItemAggMV1mByK8sCluster.ts +5 -2
- package/Models/AnalyticsModels/MetricItemAggMV1mByService.ts +5 -2
- package/Models/DatabaseModels/EnterpriseLicense.ts +21 -0
- package/Models/DatabaseModels/EnterpriseLicenseInstance.ts +25 -0
- package/Models/DatabaseModels/GlobalConfig.ts +76 -0
- package/Server/API/EnterpriseLicenseAPI.ts +57 -0
- package/Server/API/GlobalConfigAPI.ts +62 -1
- package/Server/EnvironmentConfig.ts +22 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1784659816363-AddInstanceVersionAndLatestReleaseColumns.ts +38 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1784705487674-AddEnterpriseLicenseEvaluationColumns.ts +25 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +4 -0
- package/Server/Services/AnalyticsDatabaseService.ts +61 -46
- package/Server/Services/DatabaseService.ts +66 -1
- package/Server/Services/WorkflowService.ts +100 -39
- package/Server/Types/Workflow/Components/Schedule.ts +57 -32
- package/Server/Utils/AnalyticsDatabase/InsertDedupContext.ts +59 -0
- package/Server/Utils/AnalyticsDatabase/StatementGenerator.ts +41 -4
- package/Server/Utils/Express.ts +13 -0
- package/Server/Utils/Telemetry/TelemetryFanInWriter.ts +799 -0
- package/Server/Utils/Telemetry/TelemetryWriterClient.ts +263 -0
- package/Server/Utils/Telemetry/TelemetryWriterServer.ts +240 -0
- package/Server/Utils/Telemetry/TelemetryWriterShedMetrics.ts +93 -0
- package/Tests/Models/AnalyticsModels/AnalyticsBaseModel.test.ts +122 -0
- package/Tests/Server/Services/DatabaseServiceSanitizeUpdateData.test.ts +232 -0
- package/Tests/Server/Services/UpdateOneByIdKeepsRowId.test.ts +107 -0
- package/Tests/Server/Services/WorkflowService.test.ts +308 -0
- package/Tests/Server/Utils/AnalyticsDatabase/ClusterAwareSchema.test.ts +164 -3
- package/Tests/Server/Utils/AnalyticsDatabase/StatementGenerator.test.ts +99 -0
- package/Tests/Server/Utils/Attribution.test.ts +203 -0
- package/Tests/Server/Utils/Marketing/ConversionUploadProvider.test.ts +183 -0
- package/Tests/Server/Utils/Marketing/GoogleAds.test.ts +340 -0
- package/Tests/Server/Utils/Monitor/Criteria/ExceptionMonitorCriteria.test.ts +87 -0
- package/Tests/Server/Utils/Monitor/Criteria/LogMonitorCriteria.test.ts +165 -0
- package/Tests/Server/Utils/Monitor/Criteria/TraceMonitorCriteria.test.ts +86 -0
- package/Tests/Server/Utils/Telemetry/TelemetryFanInWriter.test.ts +1565 -0
- package/Tests/Server/Utils/Telemetry/TelemetryWriterClient.test.ts +313 -0
- package/Tests/Server/Utils/Telemetry/TelemetryWriterServer.test.ts +270 -0
- package/Tests/Server/Utils/Telemetry/TelemetryWriterShedMetrics.test.ts +127 -0
- package/Tests/Types/AI/CodeFixTaskType.test.ts +3 -0
- package/Tests/Types/HashCode.test.ts +41 -0
- package/Tests/Types/Log/LogQueryParser.test.ts +186 -0
- package/Tests/Types/Monitor/MonitorCriteriaMetricVariables.test.ts +228 -0
- package/Tests/Types/Monitor/MonitorStepDefaultTelemetryConfig.test.ts +169 -0
- package/Tests/Types/Monitor/MonitorStepExceptionMonitor.test.ts +289 -0
- package/Tests/Types/Monitor/MonitorStepLogMonitor.test.ts +231 -0
- package/Tests/Types/Monitor/MonitorStepMetricViewConfigUtil.test.ts +245 -0
- package/Tests/Types/Monitor/MonitorStepNetworkDeviceMonitor.test.ts +155 -0
- package/Tests/Types/Monitor/MonitorStepTelemetrySerialization.test.ts +141 -0
- package/Tests/Types/Monitor/MonitorStepTraceMonitor.test.ts +137 -0
- package/Tests/Types/Workspace/NotificationRules/NotificationRuleCondition.test.ts +311 -0
- package/Tests/UI/Utils/Breadcrumb/BreadcrumbTrailResolver.test.ts +461 -0
- package/Tests/UI/Utils/Breadcrumb/fixtures/RealBreadcrumbTrails.ts +2852 -0
- package/Tests/UI/Utils/Breadcrumb/fixtures/RealRoutePatterns.ts +758 -0
- package/Tests/UI/Utils/NotificationMethodUtil.test.ts +564 -0
- package/Tests/Utils/Array.test.ts +156 -0
- package/Tests/Utils/CronTab.test.ts +199 -0
- package/Tests/Utils/Dashboard/VariableInterpolation.test.ts +197 -0
- package/Tests/Utils/ModelImportExport.test.ts +101 -0
- package/Tests/Utils/Number.test.ts +179 -0
- package/Tests/Utils/ValueFormatter.test.ts +305 -0
- package/Tests/Utils/VersionUtil.test.ts +348 -0
- package/Tests/jest.setup.ts +1 -0
- package/Types/AnalyticsDatabase/TableColumn.ts +23 -0
- package/Types/EnterpriseLicense/EnterpriseLicenseInstanceSummary.ts +6 -0
- package/Types/Monitor/MonitorStep.ts +24 -4
- package/Types/Monitor/MonitorStepMetricViewConfigUtil.ts +105 -0
- package/UI/Components/EditionLabel/EditionLabel.tsx +445 -12
- package/UI/Components/Workflow/ArgumentsForm.tsx +68 -30
- package/UI/Components/Workflow/CronScheduleField.tsx +411 -0
- package/UI/Utils/Breadcrumb/BreadcrumbTrailResolver.ts +176 -0
- package/UI/Utils/NotificationMethodUtil.ts +310 -0
- package/Utils/CronTab.ts +823 -0
- package/Utils/ModelImportExport.ts +21 -6
- package/Utils/VersionUtil.ts +260 -0
- package/build/dist/Models/AnalyticsModels/AnalyticsBaseModel/AnalyticsBaseModel.js +25 -20
- package/build/dist/Models/AnalyticsModels/AnalyticsBaseModel/AnalyticsBaseModel.js.map +1 -1
- package/build/dist/Models/AnalyticsModels/MetricBaselineHourly.js +2 -0
- package/build/dist/Models/AnalyticsModels/MetricBaselineHourly.js.map +1 -1
- package/build/dist/Models/AnalyticsModels/MetricItemAggMV1m.js +5 -2
- package/build/dist/Models/AnalyticsModels/MetricItemAggMV1m.js.map +1 -1
- package/build/dist/Models/AnalyticsModels/MetricItemAggMV1mByContainer.js +5 -2
- package/build/dist/Models/AnalyticsModels/MetricItemAggMV1mByContainer.js.map +1 -1
- package/build/dist/Models/AnalyticsModels/MetricItemAggMV1mByHostV2.js +5 -2
- package/build/dist/Models/AnalyticsModels/MetricItemAggMV1mByHostV2.js.map +1 -1
- package/build/dist/Models/AnalyticsModels/MetricItemAggMV1mByK8sCluster.js +5 -2
- package/build/dist/Models/AnalyticsModels/MetricItemAggMV1mByK8sCluster.js.map +1 -1
- package/build/dist/Models/AnalyticsModels/MetricItemAggMV1mByService.js +5 -2
- package/build/dist/Models/AnalyticsModels/MetricItemAggMV1mByService.js.map +1 -1
- package/build/dist/Models/DatabaseModels/EnterpriseLicense.js +22 -0
- package/build/dist/Models/DatabaseModels/EnterpriseLicense.js.map +1 -1
- package/build/dist/Models/DatabaseModels/EnterpriseLicenseInstance.js +26 -0
- package/build/dist/Models/DatabaseModels/EnterpriseLicenseInstance.js.map +1 -1
- package/build/dist/Models/DatabaseModels/GlobalConfig.js +81 -0
- package/build/dist/Models/DatabaseModels/GlobalConfig.js.map +1 -1
- package/build/dist/Server/API/EnterpriseLicenseAPI.js +47 -0
- package/build/dist/Server/API/EnterpriseLicenseAPI.js.map +1 -1
- package/build/dist/Server/API/GlobalConfigAPI.js +52 -1
- package/build/dist/Server/API/GlobalConfigAPI.js.map +1 -1
- package/build/dist/Server/EnvironmentConfig.js +17 -0
- package/build/dist/Server/EnvironmentConfig.js.map +1 -1
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1784659816363-AddInstanceVersionAndLatestReleaseColumns.js +18 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1784659816363-AddInstanceVersionAndLatestReleaseColumns.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1784705487674-AddEnterpriseLicenseEvaluationColumns.js +14 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1784705487674-AddEnterpriseLicenseEvaluationColumns.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +4 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
- package/build/dist/Server/Services/AnalyticsDatabaseService.js +53 -17
- package/build/dist/Server/Services/AnalyticsDatabaseService.js.map +1 -1
- package/build/dist/Server/Services/DatabaseService.js +53 -1
- package/build/dist/Server/Services/DatabaseService.js.map +1 -1
- package/build/dist/Server/Services/WorkflowService.js +80 -30
- package/build/dist/Server/Services/WorkflowService.js.map +1 -1
- package/build/dist/Server/Types/Workflow/Components/Schedule.js +44 -19
- package/build/dist/Server/Types/Workflow/Components/Schedule.js.map +1 -1
- package/build/dist/Server/Utils/AnalyticsDatabase/InsertDedupContext.js +24 -0
- package/build/dist/Server/Utils/AnalyticsDatabase/InsertDedupContext.js.map +1 -0
- package/build/dist/Server/Utils/AnalyticsDatabase/StatementGenerator.js +29 -4
- package/build/dist/Server/Utils/AnalyticsDatabase/StatementGenerator.js.map +1 -1
- package/build/dist/Server/Utils/Express.js +12 -0
- package/build/dist/Server/Utils/Express.js.map +1 -1
- package/build/dist/Server/Utils/Telemetry/TelemetryFanInWriter.js +496 -0
- package/build/dist/Server/Utils/Telemetry/TelemetryFanInWriter.js.map +1 -0
- package/build/dist/Server/Utils/Telemetry/TelemetryWriterClient.js +165 -0
- package/build/dist/Server/Utils/Telemetry/TelemetryWriterClient.js.map +1 -0
- package/build/dist/Server/Utils/Telemetry/TelemetryWriterServer.js +136 -0
- package/build/dist/Server/Utils/Telemetry/TelemetryWriterServer.js.map +1 -0
- package/build/dist/Server/Utils/Telemetry/TelemetryWriterShedMetrics.js +76 -0
- package/build/dist/Server/Utils/Telemetry/TelemetryWriterShedMetrics.js.map +1 -0
- package/build/dist/Types/AnalyticsDatabase/TableColumn.js +7 -0
- package/build/dist/Types/AnalyticsDatabase/TableColumn.js.map +1 -1
- package/build/dist/Types/Monitor/MonitorStep.js +20 -4
- package/build/dist/Types/Monitor/MonitorStep.js.map +1 -1
- package/build/dist/Types/Monitor/MonitorStepMetricViewConfigUtil.js +73 -0
- package/build/dist/Types/Monitor/MonitorStepMetricViewConfigUtil.js.map +1 -0
- package/build/dist/UI/Components/EditionLabel/EditionLabel.js +261 -13
- package/build/dist/UI/Components/EditionLabel/EditionLabel.js.map +1 -1
- package/build/dist/UI/Components/Workflow/ArgumentsForm.js +30 -6
- package/build/dist/UI/Components/Workflow/ArgumentsForm.js.map +1 -1
- package/build/dist/UI/Components/Workflow/CronScheduleField.js +209 -0
- package/build/dist/UI/Components/Workflow/CronScheduleField.js.map +1 -0
- package/build/dist/UI/Utils/Breadcrumb/BreadcrumbTrailResolver.js +129 -0
- package/build/dist/UI/Utils/Breadcrumb/BreadcrumbTrailResolver.js.map +1 -0
- package/build/dist/UI/Utils/NotificationMethodUtil.js +189 -0
- package/build/dist/UI/Utils/NotificationMethodUtil.js.map +1 -0
- package/build/dist/Utils/CronTab.js +609 -0
- package/build/dist/Utils/CronTab.js.map +1 -0
- package/build/dist/Utils/ModelImportExport.js +20 -6
- package/build/dist/Utils/ModelImportExport.js.map +1 -1
- package/build/dist/Utils/VersionUtil.js +193 -0
- package/build/dist/Utils/VersionUtil.js.map +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1,289 @@
|
|
|
1
|
+
import ExceptionInstance from "../../../Models/AnalyticsModels/ExceptionInstance";
|
|
2
|
+
import InBetween from "../../../Types/BaseDatabase/InBetween";
|
|
3
|
+
import Includes from "../../../Types/BaseDatabase/Includes";
|
|
4
|
+
import Query from "../../../Types/BaseDatabase/Query";
|
|
5
|
+
import Search from "../../../Types/BaseDatabase/Search";
|
|
6
|
+
import { JSONObject } from "../../../Types/JSON";
|
|
7
|
+
import MonitorStepExceptionMonitor, {
|
|
8
|
+
MonitorStepExceptionMonitorUtil,
|
|
9
|
+
} from "../../../Types/Monitor/MonitorStepExceptionMonitor";
|
|
10
|
+
import ObjectID from "../../../Types/ObjectID";
|
|
11
|
+
|
|
12
|
+
describe("MonitorStepExceptionMonitorUtil", () => {
|
|
13
|
+
describe("getDefault", () => {
|
|
14
|
+
test("returns an empty monitor scoped to the last 60 seconds", () => {
|
|
15
|
+
const def: MonitorStepExceptionMonitor =
|
|
16
|
+
MonitorStepExceptionMonitorUtil.getDefault();
|
|
17
|
+
|
|
18
|
+
expect(def.telemetryServiceIds).toEqual([]);
|
|
19
|
+
expect(def.entityKeys).toEqual([]);
|
|
20
|
+
expect(def.exceptionTypes).toEqual([]);
|
|
21
|
+
expect(def.message).toBe("");
|
|
22
|
+
expect(def.includeResolved).toBe(false);
|
|
23
|
+
expect(def.includeArchived).toBe(false);
|
|
24
|
+
expect(def.lastXSecondsOfExceptions).toBe(60);
|
|
25
|
+
});
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
describe("toAnalyticsQuery", () => {
|
|
29
|
+
test("builds no filters for the empty default when the time window is off", () => {
|
|
30
|
+
const query: Query<ExceptionInstance> =
|
|
31
|
+
MonitorStepExceptionMonitorUtil.toAnalyticsQuery({
|
|
32
|
+
...MonitorStepExceptionMonitorUtil.getDefault(),
|
|
33
|
+
lastXSecondsOfExceptions: 0,
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
expect(query).toEqual({});
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
test("scopes to telemetry services when provided", () => {
|
|
40
|
+
const serviceId: ObjectID = ObjectID.generate();
|
|
41
|
+
|
|
42
|
+
const query: Query<ExceptionInstance> =
|
|
43
|
+
MonitorStepExceptionMonitorUtil.toAnalyticsQuery({
|
|
44
|
+
...MonitorStepExceptionMonitorUtil.getDefault(),
|
|
45
|
+
telemetryServiceIds: [serviceId],
|
|
46
|
+
lastXSecondsOfExceptions: 0,
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
expect(query.primaryEntityId).toBeInstanceOf(Includes);
|
|
50
|
+
expect((query.primaryEntityId as Includes).values).toEqual([serviceId]);
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
test("scopes to entity keys when provided", () => {
|
|
54
|
+
const query: Query<ExceptionInstance> =
|
|
55
|
+
MonitorStepExceptionMonitorUtil.toAnalyticsQuery({
|
|
56
|
+
...MonitorStepExceptionMonitorUtil.getDefault(),
|
|
57
|
+
entityKeys: ["host-1", "pod-2"],
|
|
58
|
+
lastXSecondsOfExceptions: 0,
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
expect(query.entityKeys).toBeInstanceOf(Includes);
|
|
62
|
+
expect((query.entityKeys as Includes).values).toEqual([
|
|
63
|
+
"host-1",
|
|
64
|
+
"pod-2",
|
|
65
|
+
]);
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
test("omits entity keys when the list is empty or undefined", () => {
|
|
69
|
+
expect(
|
|
70
|
+
MonitorStepExceptionMonitorUtil.toAnalyticsQuery({
|
|
71
|
+
...MonitorStepExceptionMonitorUtil.getDefault(),
|
|
72
|
+
entityKeys: [],
|
|
73
|
+
lastXSecondsOfExceptions: 0,
|
|
74
|
+
}).entityKeys,
|
|
75
|
+
).toBeUndefined();
|
|
76
|
+
|
|
77
|
+
// Monitors saved before entityKeys existed carry it as undefined.
|
|
78
|
+
expect(
|
|
79
|
+
MonitorStepExceptionMonitorUtil.toAnalyticsQuery({
|
|
80
|
+
...MonitorStepExceptionMonitorUtil.getDefault(),
|
|
81
|
+
entityKeys: undefined,
|
|
82
|
+
lastXSecondsOfExceptions: 0,
|
|
83
|
+
}).entityKeys,
|
|
84
|
+
).toBeUndefined();
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
test("filters by exception type when provided", () => {
|
|
88
|
+
const query: Query<ExceptionInstance> =
|
|
89
|
+
MonitorStepExceptionMonitorUtil.toAnalyticsQuery({
|
|
90
|
+
...MonitorStepExceptionMonitorUtil.getDefault(),
|
|
91
|
+
exceptionTypes: ["TypeError", "ValueError"],
|
|
92
|
+
lastXSecondsOfExceptions: 0,
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
expect(query.exceptionType).toBeInstanceOf(Includes);
|
|
96
|
+
expect((query.exceptionType as Includes).values).toEqual([
|
|
97
|
+
"TypeError",
|
|
98
|
+
"ValueError",
|
|
99
|
+
]);
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
test("omits the exception type filter when the list is empty", () => {
|
|
103
|
+
expect(
|
|
104
|
+
MonitorStepExceptionMonitorUtil.toAnalyticsQuery({
|
|
105
|
+
...MonitorStepExceptionMonitorUtil.getDefault(),
|
|
106
|
+
exceptionTypes: [],
|
|
107
|
+
lastXSecondsOfExceptions: 0,
|
|
108
|
+
}).exceptionType,
|
|
109
|
+
).toBeUndefined();
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
test("searches the message when provided", () => {
|
|
113
|
+
const query: Query<ExceptionInstance> =
|
|
114
|
+
MonitorStepExceptionMonitorUtil.toAnalyticsQuery({
|
|
115
|
+
...MonitorStepExceptionMonitorUtil.getDefault(),
|
|
116
|
+
message: "null pointer",
|
|
117
|
+
lastXSecondsOfExceptions: 0,
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
expect(query.message).toBeInstanceOf(Search);
|
|
121
|
+
expect((query.message as Search<string>).value).toBe("null pointer");
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
test("omits the message filter when it is an empty string", () => {
|
|
125
|
+
expect(
|
|
126
|
+
MonitorStepExceptionMonitorUtil.toAnalyticsQuery({
|
|
127
|
+
...MonitorStepExceptionMonitorUtil.getDefault(),
|
|
128
|
+
message: "",
|
|
129
|
+
lastXSecondsOfExceptions: 0,
|
|
130
|
+
}).message,
|
|
131
|
+
).toBeUndefined();
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
test("builds a trailing time window from lastXSecondsOfExceptions", () => {
|
|
135
|
+
const query: Query<ExceptionInstance> =
|
|
136
|
+
MonitorStepExceptionMonitorUtil.toAnalyticsQuery({
|
|
137
|
+
...MonitorStepExceptionMonitorUtil.getDefault(),
|
|
138
|
+
lastXSecondsOfExceptions: 300,
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
expect(query.time).toBeInstanceOf(InBetween);
|
|
142
|
+
|
|
143
|
+
const time: InBetween<Date> = query.time as InBetween<Date>;
|
|
144
|
+
const spanMs: number =
|
|
145
|
+
time.endValue.getTime() - time.startValue.getTime();
|
|
146
|
+
|
|
147
|
+
expect(Math.abs(spanMs - 300 * 1000)).toBeLessThan(2000);
|
|
148
|
+
expect(time.startValue.getTime()).toBeLessThan(time.endValue.getTime());
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
test("omits the time window when lastXSecondsOfExceptions is 0", () => {
|
|
152
|
+
expect(
|
|
153
|
+
MonitorStepExceptionMonitorUtil.toAnalyticsQuery({
|
|
154
|
+
...MonitorStepExceptionMonitorUtil.getDefault(),
|
|
155
|
+
lastXSecondsOfExceptions: 0,
|
|
156
|
+
}).time,
|
|
157
|
+
).toBeUndefined();
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
test("does not encode includeResolved / includeArchived into the query", () => {
|
|
161
|
+
/*
|
|
162
|
+
* These flags are intentionally not part of the analytics query — the
|
|
163
|
+
* resolved/archived exclusion is applied by the telemetry monitor worker
|
|
164
|
+
* (see MonitorTelemetryMonitor), not here.
|
|
165
|
+
*/
|
|
166
|
+
const query: Query<ExceptionInstance> =
|
|
167
|
+
MonitorStepExceptionMonitorUtil.toAnalyticsQuery({
|
|
168
|
+
...MonitorStepExceptionMonitorUtil.getDefault(),
|
|
169
|
+
includeResolved: true,
|
|
170
|
+
includeArchived: true,
|
|
171
|
+
lastXSecondsOfExceptions: 0,
|
|
172
|
+
});
|
|
173
|
+
|
|
174
|
+
expect(query).toEqual({});
|
|
175
|
+
});
|
|
176
|
+
|
|
177
|
+
test("combines every filter when all are set", () => {
|
|
178
|
+
const query: Query<ExceptionInstance> =
|
|
179
|
+
MonitorStepExceptionMonitorUtil.toAnalyticsQuery({
|
|
180
|
+
telemetryServiceIds: [ObjectID.generate()],
|
|
181
|
+
entityKeys: ["host-1"],
|
|
182
|
+
exceptionTypes: ["TypeError"],
|
|
183
|
+
message: "boom",
|
|
184
|
+
includeResolved: false,
|
|
185
|
+
includeArchived: false,
|
|
186
|
+
lastXSecondsOfExceptions: 60,
|
|
187
|
+
});
|
|
188
|
+
|
|
189
|
+
expect(query.primaryEntityId).toBeDefined();
|
|
190
|
+
expect(query.entityKeys).toBeDefined();
|
|
191
|
+
expect(query.exceptionType).toBeDefined();
|
|
192
|
+
expect(query.message).toBeDefined();
|
|
193
|
+
expect(query.time).toBeDefined();
|
|
194
|
+
});
|
|
195
|
+
});
|
|
196
|
+
|
|
197
|
+
describe("fromJSON", () => {
|
|
198
|
+
test("fills every field with a default when the JSON is empty", () => {
|
|
199
|
+
const monitor: MonitorStepExceptionMonitor =
|
|
200
|
+
MonitorStepExceptionMonitorUtil.fromJSON({});
|
|
201
|
+
|
|
202
|
+
expect(monitor.telemetryServiceIds).toEqual([]);
|
|
203
|
+
expect(monitor.entityKeys).toEqual([]);
|
|
204
|
+
expect(monitor.exceptionTypes).toEqual([]);
|
|
205
|
+
expect(monitor.message).toBe("");
|
|
206
|
+
expect(monitor.includeResolved).toBe(false);
|
|
207
|
+
expect(monitor.includeArchived).toBe(false);
|
|
208
|
+
expect(monitor.lastXSecondsOfExceptions).toBe(60);
|
|
209
|
+
});
|
|
210
|
+
|
|
211
|
+
test("coerces the include flags to booleans", () => {
|
|
212
|
+
const monitor: MonitorStepExceptionMonitor =
|
|
213
|
+
MonitorStepExceptionMonitorUtil.fromJSON({
|
|
214
|
+
includeResolved: true,
|
|
215
|
+
includeArchived: true,
|
|
216
|
+
});
|
|
217
|
+
|
|
218
|
+
expect(monitor.includeResolved).toBe(true);
|
|
219
|
+
expect(monitor.includeArchived).toBe(true);
|
|
220
|
+
});
|
|
221
|
+
|
|
222
|
+
test("falls back to 60 seconds for a zero/absent window", () => {
|
|
223
|
+
// `|| 60` means a stored 0 is treated as "unset" and becomes 60.
|
|
224
|
+
expect(
|
|
225
|
+
MonitorStepExceptionMonitorUtil.fromJSON({
|
|
226
|
+
lastXSecondsOfExceptions: 0,
|
|
227
|
+
}).lastXSecondsOfExceptions,
|
|
228
|
+
).toBe(60);
|
|
229
|
+
|
|
230
|
+
expect(
|
|
231
|
+
MonitorStepExceptionMonitorUtil.fromJSON({
|
|
232
|
+
lastXSecondsOfExceptions: 120,
|
|
233
|
+
}).lastXSecondsOfExceptions,
|
|
234
|
+
).toBe(120);
|
|
235
|
+
});
|
|
236
|
+
});
|
|
237
|
+
|
|
238
|
+
describe("toJSON / round trip", () => {
|
|
239
|
+
test("normalizes an undefined entityKeys to an empty array", () => {
|
|
240
|
+
const json: JSONObject = MonitorStepExceptionMonitorUtil.toJSON({
|
|
241
|
+
...MonitorStepExceptionMonitorUtil.getDefault(),
|
|
242
|
+
entityKeys: undefined,
|
|
243
|
+
});
|
|
244
|
+
|
|
245
|
+
expect(json["entityKeys"]).toEqual([]);
|
|
246
|
+
});
|
|
247
|
+
|
|
248
|
+
test("round-trips a fully populated monitor", () => {
|
|
249
|
+
const original: MonitorStepExceptionMonitor = {
|
|
250
|
+
telemetryServiceIds: [ObjectID.generate()],
|
|
251
|
+
entityKeys: ["host-1"],
|
|
252
|
+
exceptionTypes: ["TypeError"],
|
|
253
|
+
message: "boom",
|
|
254
|
+
includeResolved: true,
|
|
255
|
+
includeArchived: true,
|
|
256
|
+
lastXSecondsOfExceptions: 300,
|
|
257
|
+
};
|
|
258
|
+
|
|
259
|
+
const roundTripped: MonitorStepExceptionMonitor =
|
|
260
|
+
MonitorStepExceptionMonitorUtil.fromJSON(
|
|
261
|
+
MonitorStepExceptionMonitorUtil.toJSON(original),
|
|
262
|
+
);
|
|
263
|
+
|
|
264
|
+
expect(roundTripped.entityKeys).toEqual(original.entityKeys);
|
|
265
|
+
expect(roundTripped.exceptionTypes).toEqual(original.exceptionTypes);
|
|
266
|
+
expect(roundTripped.message).toBe(original.message);
|
|
267
|
+
expect(roundTripped.includeResolved).toBe(original.includeResolved);
|
|
268
|
+
expect(roundTripped.includeArchived).toBe(original.includeArchived);
|
|
269
|
+
expect(roundTripped.lastXSecondsOfExceptions).toBe(
|
|
270
|
+
original.lastXSecondsOfExceptions,
|
|
271
|
+
);
|
|
272
|
+
expect(roundTripped.telemetryServiceIds.map(String)).toEqual(
|
|
273
|
+
original.telemetryServiceIds.map(String),
|
|
274
|
+
);
|
|
275
|
+
});
|
|
276
|
+
|
|
277
|
+
test("the default value round-trips unchanged", () => {
|
|
278
|
+
const def: MonitorStepExceptionMonitor =
|
|
279
|
+
MonitorStepExceptionMonitorUtil.getDefault();
|
|
280
|
+
|
|
281
|
+
const roundTripped: MonitorStepExceptionMonitor =
|
|
282
|
+
MonitorStepExceptionMonitorUtil.fromJSON(
|
|
283
|
+
MonitorStepExceptionMonitorUtil.toJSON(def),
|
|
284
|
+
);
|
|
285
|
+
|
|
286
|
+
expect(roundTripped).toEqual(def);
|
|
287
|
+
});
|
|
288
|
+
});
|
|
289
|
+
});
|
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
import Log from "../../../Models/AnalyticsModels/Log";
|
|
2
|
+
import Includes from "../../../Types/BaseDatabase/Includes";
|
|
3
|
+
import Query from "../../../Types/BaseDatabase/Query";
|
|
4
|
+
import Search from "../../../Types/BaseDatabase/Search";
|
|
5
|
+
import InBetween from "../../../Types/BaseDatabase/InBetween";
|
|
6
|
+
import { JSONObject } from "../../../Types/JSON";
|
|
7
|
+
import LogSeverity from "../../../Types/Log/LogSeverity";
|
|
8
|
+
import MonitorStepLogMonitor, {
|
|
9
|
+
MonitorStepLogMonitorUtil,
|
|
10
|
+
} from "../../../Types/Monitor/MonitorStepLogMonitor";
|
|
11
|
+
import ObjectID from "../../../Types/ObjectID";
|
|
12
|
+
|
|
13
|
+
describe("MonitorStepLogMonitorUtil", () => {
|
|
14
|
+
describe("getDefault", () => {
|
|
15
|
+
test("returns an empty monitor scoped to the last 60 seconds", () => {
|
|
16
|
+
const def: MonitorStepLogMonitor = MonitorStepLogMonitorUtil.getDefault();
|
|
17
|
+
|
|
18
|
+
expect(def.attributes).toEqual({});
|
|
19
|
+
expect(def.body).toBe("");
|
|
20
|
+
expect(def.severityTexts).toEqual([]);
|
|
21
|
+
expect(def.telemetryServiceIds).toEqual([]);
|
|
22
|
+
expect(def.entityKeys).toEqual([]);
|
|
23
|
+
expect(def.lastXSecondsOfLogs).toBe(60);
|
|
24
|
+
});
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
describe("toQuery", () => {
|
|
28
|
+
test("builds no filters for the empty default (other than the time window)", () => {
|
|
29
|
+
const query: Query<Log> = MonitorStepLogMonitorUtil.toQuery({
|
|
30
|
+
...MonitorStepLogMonitorUtil.getDefault(),
|
|
31
|
+
lastXSecondsOfLogs: 0, // disable the time window too
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
expect(query).toEqual({});
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
test("scopes to telemetry services when provided", () => {
|
|
38
|
+
const serviceId: ObjectID = ObjectID.generate();
|
|
39
|
+
|
|
40
|
+
const query: Query<Log> = MonitorStepLogMonitorUtil.toQuery({
|
|
41
|
+
...MonitorStepLogMonitorUtil.getDefault(),
|
|
42
|
+
telemetryServiceIds: [serviceId],
|
|
43
|
+
lastXSecondsOfLogs: 0,
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
expect(query.primaryEntityId).toBeInstanceOf(Includes);
|
|
47
|
+
expect((query.primaryEntityId as Includes).values).toEqual([serviceId]);
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
test("scopes to entity keys when provided", () => {
|
|
51
|
+
const query: Query<Log> = MonitorStepLogMonitorUtil.toQuery({
|
|
52
|
+
...MonitorStepLogMonitorUtil.getDefault(),
|
|
53
|
+
entityKeys: ["host-1", "pod-2"],
|
|
54
|
+
lastXSecondsOfLogs: 0,
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
expect(query.entityKeys).toBeInstanceOf(Includes);
|
|
58
|
+
expect((query.entityKeys as Includes).values).toEqual([
|
|
59
|
+
"host-1",
|
|
60
|
+
"pod-2",
|
|
61
|
+
]);
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
test("omits entity keys when the list is empty or undefined", () => {
|
|
65
|
+
expect(
|
|
66
|
+
MonitorStepLogMonitorUtil.toQuery({
|
|
67
|
+
...MonitorStepLogMonitorUtil.getDefault(),
|
|
68
|
+
entityKeys: [],
|
|
69
|
+
lastXSecondsOfLogs: 0,
|
|
70
|
+
}).entityKeys,
|
|
71
|
+
).toBeUndefined();
|
|
72
|
+
|
|
73
|
+
expect(
|
|
74
|
+
MonitorStepLogMonitorUtil.toQuery({
|
|
75
|
+
...MonitorStepLogMonitorUtil.getDefault(),
|
|
76
|
+
entityKeys: undefined,
|
|
77
|
+
lastXSecondsOfLogs: 0,
|
|
78
|
+
}).entityKeys,
|
|
79
|
+
).toBeUndefined();
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
test("passes attributes through when non-empty", () => {
|
|
83
|
+
const query: Query<Log> = MonitorStepLogMonitorUtil.toQuery({
|
|
84
|
+
...MonitorStepLogMonitorUtil.getDefault(),
|
|
85
|
+
attributes: { env: "prod", retries: 3, ok: true },
|
|
86
|
+
lastXSecondsOfLogs: 0,
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
expect(query.attributes).toEqual({ env: "prod", retries: 3, ok: true });
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
test("omits attributes when the dictionary is empty", () => {
|
|
93
|
+
expect(
|
|
94
|
+
MonitorStepLogMonitorUtil.toQuery({
|
|
95
|
+
...MonitorStepLogMonitorUtil.getDefault(),
|
|
96
|
+
attributes: {},
|
|
97
|
+
lastXSecondsOfLogs: 0,
|
|
98
|
+
}).attributes,
|
|
99
|
+
).toBeUndefined();
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
test("filters by severity when provided", () => {
|
|
103
|
+
const query: Query<Log> = MonitorStepLogMonitorUtil.toQuery({
|
|
104
|
+
...MonitorStepLogMonitorUtil.getDefault(),
|
|
105
|
+
severityTexts: [LogSeverity.Error, LogSeverity.Fatal],
|
|
106
|
+
lastXSecondsOfLogs: 0,
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
expect(query.severityText).toBeInstanceOf(Includes);
|
|
110
|
+
expect((query.severityText as Includes).values).toEqual([
|
|
111
|
+
LogSeverity.Error,
|
|
112
|
+
LogSeverity.Fatal,
|
|
113
|
+
]);
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
test("searches the body when a body filter is set", () => {
|
|
117
|
+
const query: Query<Log> = MonitorStepLogMonitorUtil.toQuery({
|
|
118
|
+
...MonitorStepLogMonitorUtil.getDefault(),
|
|
119
|
+
body: "connection refused",
|
|
120
|
+
lastXSecondsOfLogs: 0,
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
expect(query.body).toBeInstanceOf(Search);
|
|
124
|
+
expect((query.body as Search<string>).value).toBe("connection refused");
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
test("omits the body filter when it is an empty string", () => {
|
|
128
|
+
expect(
|
|
129
|
+
MonitorStepLogMonitorUtil.toQuery({
|
|
130
|
+
...MonitorStepLogMonitorUtil.getDefault(),
|
|
131
|
+
body: "",
|
|
132
|
+
lastXSecondsOfLogs: 0,
|
|
133
|
+
}).body,
|
|
134
|
+
).toBeUndefined();
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
test("builds a trailing time window from lastXSecondsOfLogs", () => {
|
|
138
|
+
const query: Query<Log> = MonitorStepLogMonitorUtil.toQuery({
|
|
139
|
+
...MonitorStepLogMonitorUtil.getDefault(),
|
|
140
|
+
lastXSecondsOfLogs: 120,
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
expect(query.time).toBeInstanceOf(InBetween);
|
|
144
|
+
|
|
145
|
+
const time: InBetween<Date> = query.time as InBetween<Date>;
|
|
146
|
+
const spanMs: number =
|
|
147
|
+
time.endValue.getTime() - time.startValue.getTime();
|
|
148
|
+
|
|
149
|
+
// 120 seconds back from now, within a small tolerance.
|
|
150
|
+
expect(Math.abs(spanMs - 120 * 1000)).toBeLessThan(2000);
|
|
151
|
+
expect(time.startValue.getTime()).toBeLessThan(time.endValue.getTime());
|
|
152
|
+
});
|
|
153
|
+
|
|
154
|
+
test("omits the time window when lastXSecondsOfLogs is 0", () => {
|
|
155
|
+
expect(
|
|
156
|
+
MonitorStepLogMonitorUtil.toQuery({
|
|
157
|
+
...MonitorStepLogMonitorUtil.getDefault(),
|
|
158
|
+
lastXSecondsOfLogs: 0,
|
|
159
|
+
}).time,
|
|
160
|
+
).toBeUndefined();
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
test("combines every filter when all are set", () => {
|
|
164
|
+
const serviceId: ObjectID = ObjectID.generate();
|
|
165
|
+
|
|
166
|
+
const query: Query<Log> = MonitorStepLogMonitorUtil.toQuery({
|
|
167
|
+
attributes: { env: "prod" },
|
|
168
|
+
body: "timeout",
|
|
169
|
+
severityTexts: [LogSeverity.Error],
|
|
170
|
+
telemetryServiceIds: [serviceId],
|
|
171
|
+
entityKeys: ["host-1"],
|
|
172
|
+
lastXSecondsOfLogs: 60,
|
|
173
|
+
});
|
|
174
|
+
|
|
175
|
+
expect(query.primaryEntityId).toBeDefined();
|
|
176
|
+
expect(query.entityKeys).toBeDefined();
|
|
177
|
+
expect(query.attributes).toBeDefined();
|
|
178
|
+
expect(query.severityText).toBeDefined();
|
|
179
|
+
expect(query.body).toBeDefined();
|
|
180
|
+
expect(query.time).toBeDefined();
|
|
181
|
+
});
|
|
182
|
+
});
|
|
183
|
+
|
|
184
|
+
describe("toJSON / fromJSON", () => {
|
|
185
|
+
test("round-trips a fully populated monitor", () => {
|
|
186
|
+
const original: MonitorStepLogMonitor = {
|
|
187
|
+
attributes: { env: "prod", retries: 3 },
|
|
188
|
+
body: "timeout",
|
|
189
|
+
severityTexts: [LogSeverity.Error, LogSeverity.Warning],
|
|
190
|
+
telemetryServiceIds: [ObjectID.generate()],
|
|
191
|
+
entityKeys: ["host-1"],
|
|
192
|
+
lastXSecondsOfLogs: 300,
|
|
193
|
+
};
|
|
194
|
+
|
|
195
|
+
const roundTripped: MonitorStepLogMonitor =
|
|
196
|
+
MonitorStepLogMonitorUtil.fromJSON(
|
|
197
|
+
MonitorStepLogMonitorUtil.toJSON(original),
|
|
198
|
+
);
|
|
199
|
+
|
|
200
|
+
expect(roundTripped.attributes).toEqual(original.attributes);
|
|
201
|
+
expect(roundTripped.body).toBe(original.body);
|
|
202
|
+
expect(roundTripped.severityTexts).toEqual(original.severityTexts);
|
|
203
|
+
expect(roundTripped.entityKeys).toEqual(original.entityKeys);
|
|
204
|
+
expect(roundTripped.lastXSecondsOfLogs).toBe(original.lastXSecondsOfLogs);
|
|
205
|
+
expect(roundTripped.telemetryServiceIds.map(String)).toEqual(
|
|
206
|
+
original.telemetryServiceIds.map(String),
|
|
207
|
+
);
|
|
208
|
+
});
|
|
209
|
+
|
|
210
|
+
test("fromJSON defaults attributes and entityKeys when absent", () => {
|
|
211
|
+
const monitor: MonitorStepLogMonitor = MonitorStepLogMonitorUtil.fromJSON(
|
|
212
|
+
{
|
|
213
|
+
telemetryServiceIds: [],
|
|
214
|
+
} as JSONObject,
|
|
215
|
+
);
|
|
216
|
+
|
|
217
|
+
expect(monitor.attributes).toEqual({});
|
|
218
|
+
// entityKeys is optional on older saved monitors — normalized to [].
|
|
219
|
+
expect(monitor.entityKeys).toEqual([]);
|
|
220
|
+
});
|
|
221
|
+
|
|
222
|
+
test("toJSON normalizes an undefined entityKeys to an empty array", () => {
|
|
223
|
+
const json: JSONObject = MonitorStepLogMonitorUtil.toJSON({
|
|
224
|
+
...MonitorStepLogMonitorUtil.getDefault(),
|
|
225
|
+
entityKeys: undefined,
|
|
226
|
+
});
|
|
227
|
+
|
|
228
|
+
expect(json["entityKeys"]).toEqual([]);
|
|
229
|
+
});
|
|
230
|
+
});
|
|
231
|
+
});
|