@oneuptime/common 14.0.5 → 14.0.6
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/Server/Services/MetricService.ts +1 -1
- package/Server/Types/Database/QueryHelper.ts +54 -1
- package/Server/Utils/AI/Toolbox/MetricTools.ts +13 -2
- package/Server/Utils/AI/Toolbox/ResourceTools.ts +12 -1
- package/Server/Utils/AnalyticsDatabase/StatementGenerator.ts +1 -1
- package/Server/Utils/Monitor/Criteria/CompareCriteria.ts +33 -0
- package/Server/Utils/Monitor/Criteria/MetricMonitorCriteria.ts +4 -3
- package/Server/Utils/Monitor/MonitorCriteriaEvaluator.ts +3 -1
- package/Tests/App/Dashboard/NetworkTopologyExplorerSearch.test.tsx +1267 -0
- package/Tests/App/Dashboard/ResourceOverviewTileTooltips.test.tsx +4 -1
- package/Tests/App/Dashboard/RumOverviewPage.test.tsx +127 -0
- package/Tests/App/Dashboard/SiteSearchBox.test.tsx +2110 -0
- package/Tests/App/Dashboard/TelemetryMetricsSignals.test.ts +168 -8
- package/Tests/Server/Services/MetricServiceAggregate.test.ts +12 -0
- package/Tests/Server/Services/SavedViewDefaults.test.ts +325 -0
- package/Tests/Server/Services/StatusPageCertificateService.test.ts +169 -0
- package/Tests/Server/Services/TeamComplianceSettingService.test.ts +191 -0
- package/Tests/Server/Types/Database/QueryHelperSearchAllWords.test.ts +651 -0
- package/Tests/Server/Utils/AI/AlertWriteTools.test.ts +256 -0
- package/Tests/Server/Utils/AI/IncidentWriteTools.test.ts +482 -0
- package/Tests/Server/Utils/Monitor/Criteria/CompareCriteria.test.ts +54 -0
- package/Tests/Server/Utils/Monitor/MetricDecimalThreshold.test.ts +417 -0
- package/Tests/Server/Utils/Monitor/MonitorCriteriaEvaluatorAffectedResourceEdgeCases.test.ts +96 -0
- package/Tests/Types/BaseDatabase/AggregationType.test.ts +5 -1
- package/Tests/Types/Dashboard/KubernetesDashboardTemplate.test.ts +184 -0
- package/Tests/Types/Dashboard/KubernetesDashboardTemplates.test.ts +107 -0
- package/Tests/Types/Monitor/KubernetesAlertTemplates.test.ts +8 -14
- package/Tests/Types/Monitor/KubernetesMetricCatalog.test.ts +4 -3
- package/Tests/Types/Monitor/Utils/KubernetesAgentEmittedMetrics.ts +27 -6
- package/Tests/UI/Rum/ChunkLoader.test.ts +76 -0
- package/Tests/UI/Rum/ReplayRailDetail.test.tsx +53 -0
- package/Tests/UI/Rum/ReplaySignals.test.ts +54 -0
- package/Tests/Utils/Dashboard/KubernetesClusterCpuTileRepair.test.ts +370 -0
- package/Tests/Utils/Rules/MonitorTypeRuleCriteria.test.ts +181 -0
- package/Types/BaseDatabase/AggregationType.ts +7 -0
- package/Types/Dashboard/DashboardTemplates.ts +20 -7
- package/Types/Rum/SessionReplayCustomEvents.ts +29 -3
- package/Types/Rum/WebVitals.ts +13 -0
- package/UI/Components/Input/Input.tsx +11 -0
- package/Utils/Dashboard/KubernetesClusterCpuTileRepair.ts +147 -0
- package/build/dist/Server/Services/MetricService.js +1 -1
- package/build/dist/Server/Types/Database/QueryHelper.js +47 -1
- package/build/dist/Server/Types/Database/QueryHelper.js.map +1 -1
- package/build/dist/Server/Utils/AI/Toolbox/MetricTools.js +13 -2
- package/build/dist/Server/Utils/AI/Toolbox/MetricTools.js.map +1 -1
- package/build/dist/Server/Utils/AI/Toolbox/ResourceTools.js +12 -1
- package/build/dist/Server/Utils/AI/Toolbox/ResourceTools.js.map +1 -1
- package/build/dist/Server/Utils/AnalyticsDatabase/StatementGenerator.js +1 -1
- package/build/dist/Server/Utils/Monitor/Criteria/CompareCriteria.js +31 -0
- package/build/dist/Server/Utils/Monitor/Criteria/CompareCriteria.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/Criteria/MetricMonitorCriteria.js +1 -1
- package/build/dist/Server/Utils/Monitor/Criteria/MetricMonitorCriteria.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/MonitorCriteriaEvaluator.js +1 -1
- package/build/dist/Server/Utils/Monitor/MonitorCriteriaEvaluator.js.map +1 -1
- package/build/dist/Types/BaseDatabase/AggregationType.js +7 -0
- package/build/dist/Types/BaseDatabase/AggregationType.js.map +1 -1
- package/build/dist/Types/Dashboard/DashboardTemplates.js +20 -7
- package/build/dist/Types/Dashboard/DashboardTemplates.js.map +1 -1
- package/build/dist/Types/Rum/SessionReplayCustomEvents.js.map +1 -1
- package/build/dist/Types/Rum/WebVitals.js +12 -0
- package/build/dist/Types/Rum/WebVitals.js.map +1 -1
- package/build/dist/UI/Components/Input/Input.js +1 -1
- package/build/dist/UI/Components/Input/Input.js.map +1 -1
- package/build/dist/Utils/Dashboard/KubernetesClusterCpuTileRepair.js +110 -0
- package/build/dist/Utils/Dashboard/KubernetesClusterCpuTileRepair.js.map +1 -0
- package/package.json +1 -1
|
@@ -952,7 +952,7 @@ export class MetricService extends AnalyticsDatabaseService<Metric> {
|
|
|
952
952
|
*
|
|
953
953
|
* For non-percentile aggregations (Sum/Avg/Min/Max/Count) we delegate
|
|
954
954
|
* to the base implementation. For percentile aggregations
|
|
955
|
-
* (P50/P90/P95/P99) we build a subquery that fans each metric row out
|
|
955
|
+
* (P50/P75/P90/P95/P99) we build a subquery that fans each metric row out
|
|
956
956
|
* into one or more `(midpoint, weight)` samples — derived from
|
|
957
957
|
* histogram buckets when present — and then runs
|
|
958
958
|
* `quantileExactWeighted` over the fanned-out distribution. This means
|
|
@@ -9,7 +9,10 @@ import { FindOperator, Raw } from "typeorm";
|
|
|
9
9
|
import { FindWhereProperty } from "../../../Types/BaseDatabase/Query";
|
|
10
10
|
import { toLikePattern } from "../../../Types/BaseDatabase/WildcardPattern";
|
|
11
11
|
import CaptureSpan from "../../Utils/Telemetry/CaptureSpan";
|
|
12
|
-
import buildJSONColumnQuery, {
|
|
12
|
+
import buildJSONColumnQuery, {
|
|
13
|
+
JSONColumnQuery,
|
|
14
|
+
escapeLikePattern,
|
|
15
|
+
} from "./JSONColumnQuery";
|
|
13
16
|
|
|
14
17
|
export type { FindOperator };
|
|
15
18
|
|
|
@@ -229,6 +232,56 @@ export default class QueryHelper {
|
|
|
229
232
|
);
|
|
230
233
|
}
|
|
231
234
|
|
|
235
|
+
/*
|
|
236
|
+
* Every word has to appear somewhere in the column, in any order.
|
|
237
|
+
*
|
|
238
|
+
* `search` is one substring, so "michigan 104822" misses a row called
|
|
239
|
+
* "Unit 104822 - Michigan Ave" even though both words are in it. Here each
|
|
240
|
+
* word gets its own ILIKE, AND-joined, which is how people recall a name
|
|
241
|
+
* they half remember.
|
|
242
|
+
*
|
|
243
|
+
* A word is matched literally: a `%` or `_` somebody typed is escaped
|
|
244
|
+
* rather than read as a wildcard.
|
|
245
|
+
*
|
|
246
|
+
* No words matches NOTHING. An AND over zero predicates is vacuously true,
|
|
247
|
+
* and "every row in the table" is never what an empty search box meant.
|
|
248
|
+
*/
|
|
249
|
+
@CaptureSpan()
|
|
250
|
+
public static searchAllWords(words: Array<string>): FindWhereProperty<any> {
|
|
251
|
+
const rids: Array<string> = [];
|
|
252
|
+
const valuesObj: Dictionary<string> = {};
|
|
253
|
+
|
|
254
|
+
for (const word of words) {
|
|
255
|
+
const trimmed: string = (word || "").trim();
|
|
256
|
+
if (!trimmed) {
|
|
257
|
+
continue;
|
|
258
|
+
}
|
|
259
|
+
const rid: string = Text.generateRandomText(10);
|
|
260
|
+
rids.push(rid);
|
|
261
|
+
valuesObj[rid] = `%${escapeLikePattern(trimmed)}%`;
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
if (rids.length === 0) {
|
|
265
|
+
return Raw(() => {
|
|
266
|
+
return `TRUE = FALSE`; // this will always return false
|
|
267
|
+
}, {});
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
return Raw(
|
|
271
|
+
(alias: string) => {
|
|
272
|
+
const conditions: string = rids
|
|
273
|
+
.map((rid: string) => {
|
|
274
|
+
return `CAST(${alias} AS TEXT) ILIKE :${rid}`;
|
|
275
|
+
})
|
|
276
|
+
.join(" AND ");
|
|
277
|
+
return `(${conditions})`;
|
|
278
|
+
},
|
|
279
|
+
{
|
|
280
|
+
...valuesObj,
|
|
281
|
+
},
|
|
282
|
+
);
|
|
283
|
+
}
|
|
284
|
+
|
|
232
285
|
/**
|
|
233
286
|
* Searches the provided entity property names with a single OR-joined ILIKE.
|
|
234
287
|
*
|
|
@@ -49,7 +49,7 @@ const METRIC_READ_PERMISSIONS: Array<Permission> = [
|
|
|
49
49
|
export const QueryMetricsTool: ObservabilityTool = {
|
|
50
50
|
name: "query_metrics",
|
|
51
51
|
description:
|
|
52
|
-
"Aggregate a metric over time: Avg, Max, Min, Sum, Count or P50/P90/P95/P99 percentiles (histogram-aware). Requires the exact metric name — discover names via lookup_context. Monitor metrics use reserved names like oneuptime.monitor.response.time with the monitor's ID as entityId.",
|
|
52
|
+
"Aggregate a metric over time: Avg, Max, Min, Sum, Count or P50/P75/P90/P95/P99 percentiles (histogram-aware). Requires the exact metric name — discover names via lookup_context. Monitor metrics use reserved names like oneuptime.monitor.response.time with the monitor's ID as entityId.",
|
|
53
53
|
inputSchema: {
|
|
54
54
|
type: "object",
|
|
55
55
|
properties: {
|
|
@@ -60,7 +60,18 @@ export const QueryMetricsTool: ObservabilityTool = {
|
|
|
60
60
|
},
|
|
61
61
|
aggregationType: {
|
|
62
62
|
type: "string",
|
|
63
|
-
enum: [
|
|
63
|
+
enum: [
|
|
64
|
+
"Avg",
|
|
65
|
+
"Max",
|
|
66
|
+
"Min",
|
|
67
|
+
"Sum",
|
|
68
|
+
"Count",
|
|
69
|
+
"P50",
|
|
70
|
+
"P75",
|
|
71
|
+
"P90",
|
|
72
|
+
"P95",
|
|
73
|
+
"P99",
|
|
74
|
+
],
|
|
64
75
|
description: "How to aggregate (default Avg).",
|
|
65
76
|
},
|
|
66
77
|
entityId: {
|
|
@@ -673,7 +673,18 @@ export const QueryResourceTelemetryTool: ObservabilityTool = {
|
|
|
673
673
|
},
|
|
674
674
|
aggregationType: {
|
|
675
675
|
type: "string",
|
|
676
|
-
enum: [
|
|
676
|
+
enum: [
|
|
677
|
+
"Avg",
|
|
678
|
+
"Min",
|
|
679
|
+
"Max",
|
|
680
|
+
"Sum",
|
|
681
|
+
"Count",
|
|
682
|
+
"P50",
|
|
683
|
+
"P75",
|
|
684
|
+
"P90",
|
|
685
|
+
"P95",
|
|
686
|
+
"P99",
|
|
687
|
+
],
|
|
677
688
|
description:
|
|
678
689
|
"Metric aggregation (defaultAvg); counter sums are exported values, not derived rates.",
|
|
679
690
|
},
|
|
@@ -1938,7 +1938,7 @@ export default class StatementGenerator<TBaseModel extends AnalyticsBaseModel> {
|
|
|
1938
1938
|
* EXAMPLE:
|
|
1939
1939
|
* SELECT sum(Metric.value) as avg_value, date_trunc('hour', toStartOfInterval(createdAt, INTERVAL 1 hour)) as createdAt
|
|
1940
1940
|
*
|
|
1941
|
-
* Percentile aggregations (P50/P90/P95/P99) compile to ClickHouse's
|
|
1941
|
+
* Percentile aggregations (P50/P75/P90/P95/P99) compile to ClickHouse's
|
|
1942
1942
|
* `quantile(level)(column)`. This is the right thing for scalar
|
|
1943
1943
|
* columns (Span.duration, Metric.value when the metric is a Sum or
|
|
1944
1944
|
* Gauge, etc.). MetricService overrides this method when it has
|
|
@@ -280,6 +280,39 @@ export default class CompareCriteria {
|
|
|
280
280
|
return threshold as number;
|
|
281
281
|
}
|
|
282
282
|
|
|
283
|
+
/*
|
|
284
|
+
* A metric-value threshold as a number, fraction included.
|
|
285
|
+
*
|
|
286
|
+
* The criteria form saves what the user typed as a STRING, and
|
|
287
|
+
* convertToNumber's parseInt truncated it: "0.9" on a ratio metric was
|
|
288
|
+
* compared as 0 and fired on every non-zero sample, and "85.5" was
|
|
289
|
+
* compared as 85. Metric values are where a fractional threshold is the
|
|
290
|
+
* natural one to type (ratios, seconds, load averages), so they are
|
|
291
|
+
* parsed with parseFloat. Every other checkOn keeps convertToNumber.
|
|
292
|
+
*
|
|
293
|
+
* Anything that does not parse to a finite number is treated as missing,
|
|
294
|
+
* so the caller ignores the filter instead of comparing against NaN.
|
|
295
|
+
*/
|
|
296
|
+
@CaptureSpan()
|
|
297
|
+
public static convertMetricThresholdToNumber(
|
|
298
|
+
threshold: string | number | undefined,
|
|
299
|
+
): number | null {
|
|
300
|
+
if (threshold === undefined || threshold === null) {
|
|
301
|
+
return null;
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
const parsed: number =
|
|
305
|
+
typeof threshold === Typeof.String
|
|
306
|
+
? parseFloat(threshold as string)
|
|
307
|
+
: (threshold as number);
|
|
308
|
+
|
|
309
|
+
if (typeof parsed !== Typeof.Number || !Number.isFinite(parsed)) {
|
|
310
|
+
return null;
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
return parsed;
|
|
314
|
+
}
|
|
315
|
+
|
|
283
316
|
@CaptureSpan()
|
|
284
317
|
public static checkEqualToOrNotEqualTo(data: {
|
|
285
318
|
value: string | number;
|
|
@@ -180,9 +180,10 @@ export default class MetricMonitorCriteria {
|
|
|
180
180
|
projectId: { toString(): string } | undefined;
|
|
181
181
|
nativeUnitsByMetricName?: { [key: string]: string } | undefined;
|
|
182
182
|
}): Promise<MetricSeriesEvaluationResult> {
|
|
183
|
-
const rawThreshold: number | null =
|
|
184
|
-
|
|
185
|
-
|
|
183
|
+
const rawThreshold: number | null =
|
|
184
|
+
CompareCriteria.convertMetricThresholdToNumber(
|
|
185
|
+
input.criteriaFilter.value,
|
|
186
|
+
);
|
|
186
187
|
|
|
187
188
|
const metricAlias: string =
|
|
188
189
|
input.criteriaFilter.metricMonitorOptions?.metricAlias || "";
|
|
@@ -4659,7 +4659,9 @@ ${contextBlock}
|
|
|
4659
4659
|
.map((f: CriteriaFilter) => {
|
|
4660
4660
|
return {
|
|
4661
4661
|
filter: f,
|
|
4662
|
-
threshold: CompareCriteria.
|
|
4662
|
+
threshold: CompareCriteria.convertMetricThresholdToNumber(
|
|
4663
|
+
f.value,
|
|
4664
|
+
) as number,
|
|
4663
4665
|
};
|
|
4664
4666
|
})
|
|
4665
4667
|
.filter((f: { filter: CriteriaFilter; threshold: number | null }) => {
|