@oneuptime/common 8.0.5386 → 8.0.5403
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/Index.ts +0 -2
- package/Models/DatabaseModels/TelemetryException.ts +0 -7
- package/Server/API/MicrosoftTeamsAPI.ts +5 -4
- package/Server/API/UserOnCallLogTimelineAPI.ts +21 -17
- package/Server/DatabaseConfig.ts +7 -2
- package/Server/EnvironmentConfig.ts +20 -7
- package/Server/Images/MicrosoftTeams/outline.png +0 -0
- package/Server/Infrastructure/GlobalCache.ts +12 -5
- package/Server/Services/AlertService.ts +0 -10
- package/Server/Services/AnalyticsDatabaseService.ts +5 -0
- package/Server/Services/IncidentService.ts +0 -10
- package/Server/Services/Index.ts +0 -2
- package/Server/Services/TeamMemberService.ts +11 -2
- package/Server/Services/TelemetryAttributeService.ts +261 -48
- package/Server/Utils/Monitor/MonitorResource.ts +0 -16
- package/Server/Utils/Telemetry/Telemetry.ts +0 -61
- package/Types/Permission.ts +0 -3
- package/UI/Components/Filters/FilterViewer.tsx +5 -1
- package/UI/Components/Filters/FiltersForm.tsx +8 -1
- package/UI/Components/List/List.tsx +4 -0
- package/UI/Components/LogsViewer/LogsViewer.tsx +102 -55
- package/UI/Components/Markdown.tsx/MarkdownViewer.tsx +1 -1
- package/UI/Components/ModelTable/BaseModelTable.tsx +6 -0
- package/UI/Components/Table/Table.tsx +4 -0
- package/UI/Config.ts +28 -19
- package/UI/Utils/API/ApiDocsAPI.ts +6 -1
- package/UI/Utils/API/DashboardAPI.ts +2 -1
- package/UI/Utils/API/IdentityAPI.ts +6 -1
- package/build/dist/Models/AnalyticsModels/Index.js +0 -2
- package/build/dist/Models/AnalyticsModels/Index.js.map +1 -1
- package/build/dist/Models/DatabaseModels/TelemetryException.js +0 -7
- package/build/dist/Models/DatabaseModels/TelemetryException.js.map +1 -1
- package/build/dist/Server/API/MicrosoftTeamsAPI.js +5 -4
- package/build/dist/Server/API/MicrosoftTeamsAPI.js.map +1 -1
- package/build/dist/Server/API/UserOnCallLogTimelineAPI.js +6 -3
- package/build/dist/Server/API/UserOnCallLogTimelineAPI.js.map +1 -1
- package/build/dist/Server/DatabaseConfig.js +3 -2
- package/build/dist/Server/DatabaseConfig.js.map +1 -1
- package/build/dist/Server/EnvironmentConfig.js +8 -7
- package/build/dist/Server/EnvironmentConfig.js.map +1 -1
- package/build/dist/Server/Infrastructure/GlobalCache.js +11 -9
- package/build/dist/Server/Infrastructure/GlobalCache.js.map +1 -1
- package/build/dist/Server/Services/AlertService.js +0 -9
- package/build/dist/Server/Services/AlertService.js.map +1 -1
- package/build/dist/Server/Services/AnalyticsDatabaseService.js.map +1 -1
- package/build/dist/Server/Services/IncidentService.js +0 -9
- package/build/dist/Server/Services/IncidentService.js.map +1 -1
- package/build/dist/Server/Services/Index.js +0 -2
- package/build/dist/Server/Services/Index.js.map +1 -1
- package/build/dist/Server/Services/TeamMemberService.js +3 -2
- package/build/dist/Server/Services/TeamMemberService.js.map +1 -1
- package/build/dist/Server/Services/TelemetryAttributeService.js +165 -46
- package/build/dist/Server/Services/TelemetryAttributeService.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/MonitorResource.js +0 -15
- package/build/dist/Server/Utils/Monitor/MonitorResource.js.map +1 -1
- package/build/dist/Server/Utils/Telemetry/Telemetry.js +0 -41
- package/build/dist/Server/Utils/Telemetry/Telemetry.js.map +1 -1
- package/build/dist/Types/Permission.js +0 -2
- package/build/dist/Types/Permission.js.map +1 -1
- package/build/dist/UI/Components/Filters/FilterViewer.js +2 -2
- package/build/dist/UI/Components/Filters/FilterViewer.js.map +1 -1
- package/build/dist/UI/Components/Filters/FiltersForm.js +6 -1
- package/build/dist/UI/Components/Filters/FiltersForm.js.map +1 -1
- package/build/dist/UI/Components/List/List.js +1 -1
- package/build/dist/UI/Components/List/List.js.map +1 -1
- package/build/dist/UI/Components/LogsViewer/LogsViewer.js +43 -16
- package/build/dist/UI/Components/LogsViewer/LogsViewer.js.map +1 -1
- package/build/dist/UI/Components/Markdown.tsx/MarkdownViewer.js +1 -1
- package/build/dist/UI/Components/Markdown.tsx/MarkdownViewer.js.map +1 -1
- package/build/dist/UI/Components/ModelTable/BaseModelTable.js +2 -2
- package/build/dist/UI/Components/ModelTable/BaseModelTable.js.map +1 -1
- package/build/dist/UI/Components/Table/Table.js +1 -1
- package/build/dist/UI/Components/Table/Table.js.map +1 -1
- package/build/dist/UI/Config.js +20 -19
- package/build/dist/UI/Config.js.map +1 -1
- package/build/dist/UI/Utils/API/ApiDocsAPI.js +2 -1
- package/build/dist/UI/Utils/API/ApiDocsAPI.js.map +1 -1
- package/build/dist/UI/Utils/API/DashboardAPI.js +2 -1
- package/build/dist/UI/Utils/API/DashboardAPI.js.map +1 -1
- package/build/dist/UI/Utils/API/IdentityAPI.js +2 -1
- package/build/dist/UI/Utils/API/IdentityAPI.js.map +1 -1
- package/package.json +1 -1
- package/Models/AnalyticsModels/TelemetryAttribute.ts +0 -164
- package/build/dist/Models/AnalyticsModels/TelemetryAttribute.js +0 -154
- package/build/dist/Models/AnalyticsModels/TelemetryAttribute.js.map +0 -1
|
@@ -1,13 +1,66 @@
|
|
|
1
|
+
import { SQL, Statement } from "../Utils/AnalyticsDatabase/Statement";
|
|
1
2
|
import TelemetryType from "../../Types/Telemetry/TelemetryType";
|
|
2
|
-
import
|
|
3
|
-
import
|
|
4
|
-
import
|
|
3
|
+
import LogDatabaseService from "./LogService";
|
|
4
|
+
import MetricDatabaseService from "./MetricService";
|
|
5
|
+
import SpanDatabaseService from "./SpanService";
|
|
6
|
+
import TableColumnType from "../../Types/AnalyticsDatabase/TableColumnType";
|
|
7
|
+
import { JSONObject } from "../../Types/JSON";
|
|
5
8
|
import ObjectID from "../../Types/ObjectID";
|
|
9
|
+
import OneUptimeDate from "../../Types/Date";
|
|
10
|
+
import GlobalCache from "../Infrastructure/GlobalCache";
|
|
6
11
|
import CaptureSpan from "../Utils/Telemetry/CaptureSpan";
|
|
12
|
+
import AnalyticsDatabaseService, {
|
|
13
|
+
DbJSONResponse,
|
|
14
|
+
Results,
|
|
15
|
+
} from "./AnalyticsDatabaseService";
|
|
7
16
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
17
|
+
type TelemetrySource = {
|
|
18
|
+
service: AnalyticsDatabaseService<any>;
|
|
19
|
+
tableName: string;
|
|
20
|
+
attributesColumn: string;
|
|
21
|
+
timeColumn: string;
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
type TelemetryAttributesCacheEntry = {
|
|
25
|
+
attributes: Array<string>;
|
|
26
|
+
refreshedAt: Date;
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
export class TelemetryAttributeService {
|
|
30
|
+
private static readonly ATTRIBUTES_LIMIT: number = 5000;
|
|
31
|
+
private static readonly ROW_SCAN_LIMIT: number = 10000;
|
|
32
|
+
private static readonly CACHE_NAMESPACE: string = "telemetry-attributes";
|
|
33
|
+
private static readonly CACHE_STALE_AFTER_MINUTES: number = 5;
|
|
34
|
+
private static readonly LOOKBACK_WINDOW_IN_DAYS: number = 30;
|
|
35
|
+
|
|
36
|
+
private getTelemetrySource(
|
|
37
|
+
telemetryType: TelemetryType,
|
|
38
|
+
): TelemetrySource | null {
|
|
39
|
+
switch (telemetryType) {
|
|
40
|
+
case TelemetryType.Log:
|
|
41
|
+
return {
|
|
42
|
+
service: LogDatabaseService,
|
|
43
|
+
tableName: LogDatabaseService.model.tableName,
|
|
44
|
+
attributesColumn: "attributes",
|
|
45
|
+
timeColumn: "time",
|
|
46
|
+
};
|
|
47
|
+
case TelemetryType.Metric:
|
|
48
|
+
return {
|
|
49
|
+
service: MetricDatabaseService,
|
|
50
|
+
tableName: MetricDatabaseService.model.tableName,
|
|
51
|
+
attributesColumn: "attributes",
|
|
52
|
+
timeColumn: "time",
|
|
53
|
+
};
|
|
54
|
+
case TelemetryType.Trace:
|
|
55
|
+
return {
|
|
56
|
+
service: SpanDatabaseService,
|
|
57
|
+
tableName: SpanDatabaseService.model.tableName,
|
|
58
|
+
attributesColumn: "attributes",
|
|
59
|
+
timeColumn: "startTime",
|
|
60
|
+
};
|
|
61
|
+
default:
|
|
62
|
+
return null;
|
|
63
|
+
}
|
|
11
64
|
}
|
|
12
65
|
|
|
13
66
|
@CaptureSpan()
|
|
@@ -15,57 +68,217 @@ export class TelemetryAttributeService extends AnalyticsDatabaseService<Telemetr
|
|
|
15
68
|
projectId: ObjectID;
|
|
16
69
|
telemetryType: TelemetryType;
|
|
17
70
|
}): Promise<string[]> {
|
|
18
|
-
const
|
|
19
|
-
|
|
71
|
+
const source: TelemetrySource | null = this.getTelemetrySource(
|
|
72
|
+
data.telemetryType,
|
|
73
|
+
);
|
|
74
|
+
|
|
75
|
+
if (!source) {
|
|
76
|
+
return [];
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
const cacheKey: string = TelemetryAttributeService.getCacheKey(
|
|
80
|
+
data.projectId,
|
|
81
|
+
data.telemetryType,
|
|
82
|
+
);
|
|
83
|
+
|
|
84
|
+
const cachedEntry: TelemetryAttributesCacheEntry | null =
|
|
85
|
+
await TelemetryAttributeService.getCachedAttributes(cacheKey);
|
|
86
|
+
|
|
87
|
+
if (cachedEntry && TelemetryAttributeService.isCacheFresh(cachedEntry)) {
|
|
88
|
+
return cachedEntry.attributes;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
let attributes: Array<string> = [];
|
|
92
|
+
|
|
93
|
+
try {
|
|
94
|
+
attributes = await TelemetryAttributeService.fetchAttributesFromDatabase({
|
|
20
95
|
projectId: data.projectId,
|
|
21
|
-
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
96
|
+
source,
|
|
97
|
+
});
|
|
98
|
+
} catch (error) {
|
|
99
|
+
if (cachedEntry) {
|
|
100
|
+
return cachedEntry.attributes;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
throw error;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
await TelemetryAttributeService.storeAttributesInCache(
|
|
107
|
+
cacheKey,
|
|
108
|
+
attributes,
|
|
109
|
+
);
|
|
110
|
+
|
|
111
|
+
if (attributes.length === 0 && cachedEntry) {
|
|
112
|
+
return cachedEntry.attributes;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
return attributes;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
private static getCacheKey(
|
|
119
|
+
projectId: ObjectID,
|
|
120
|
+
telemetryType: TelemetryType,
|
|
121
|
+
): string {
|
|
122
|
+
return `${projectId.toString()}:${telemetryType}`;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
private static getLookbackStartDate(): Date {
|
|
126
|
+
return OneUptimeDate.addRemoveDays(
|
|
127
|
+
OneUptimeDate.getCurrentDate(),
|
|
128
|
+
-TelemetryAttributeService.LOOKBACK_WINDOW_IN_DAYS,
|
|
129
|
+
);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
private static async getCachedAttributes(
|
|
133
|
+
cacheKey: string,
|
|
134
|
+
): Promise<TelemetryAttributesCacheEntry | null> {
|
|
135
|
+
let payload: JSONObject | null = null;
|
|
136
|
+
|
|
137
|
+
try {
|
|
138
|
+
payload = await GlobalCache.getJSONObject(
|
|
139
|
+
TelemetryAttributeService.CACHE_NAMESPACE,
|
|
140
|
+
cacheKey,
|
|
141
|
+
);
|
|
142
|
+
} catch {
|
|
143
|
+
return null;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
if (!payload) {
|
|
147
|
+
return null;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
const attributesValue: JSONObject["attributes"] = payload["attributes"];
|
|
151
|
+
const refreshedAtValue: JSONObject["refreshedAt"] = payload["refreshedAt"];
|
|
152
|
+
|
|
153
|
+
if (
|
|
154
|
+
!Array.isArray(attributesValue) ||
|
|
155
|
+
typeof refreshedAtValue !== "string"
|
|
156
|
+
) {
|
|
157
|
+
return null;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
const attributeCandidates: Array<unknown> =
|
|
161
|
+
attributesValue as Array<unknown>;
|
|
162
|
+
|
|
163
|
+
const attributes: Array<string> = attributeCandidates.filter(
|
|
164
|
+
(attribute: unknown): attribute is string => {
|
|
165
|
+
return typeof attribute === "string";
|
|
28
166
|
},
|
|
29
|
-
|
|
167
|
+
);
|
|
30
168
|
|
|
31
|
-
return
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
: [];
|
|
169
|
+
return {
|
|
170
|
+
attributes,
|
|
171
|
+
refreshedAt: OneUptimeDate.fromString(refreshedAtValue),
|
|
172
|
+
};
|
|
36
173
|
}
|
|
37
174
|
|
|
38
|
-
|
|
39
|
-
|
|
175
|
+
private static isCacheFresh(
|
|
176
|
+
cacheEntry: TelemetryAttributesCacheEntry,
|
|
177
|
+
): boolean {
|
|
178
|
+
const now: Date = OneUptimeDate.getCurrentDate();
|
|
179
|
+
const minutesSinceRefresh: number = Math.abs(
|
|
180
|
+
OneUptimeDate.getNumberOfMinutesBetweenDates(cacheEntry.refreshedAt, now),
|
|
181
|
+
);
|
|
182
|
+
|
|
183
|
+
return (
|
|
184
|
+
minutesSinceRefresh <= TelemetryAttributeService.CACHE_STALE_AFTER_MINUTES
|
|
185
|
+
);
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
private static async storeAttributesInCache(
|
|
189
|
+
cacheKey: string,
|
|
190
|
+
attributes: Array<string>,
|
|
191
|
+
): Promise<void> {
|
|
192
|
+
const payload: JSONObject = {
|
|
193
|
+
attributes,
|
|
194
|
+
refreshedAt: OneUptimeDate.getCurrentDate().toISOString(),
|
|
195
|
+
};
|
|
196
|
+
|
|
197
|
+
try {
|
|
198
|
+
await GlobalCache.setJSON(
|
|
199
|
+
TelemetryAttributeService.CACHE_NAMESPACE,
|
|
200
|
+
cacheKey,
|
|
201
|
+
payload,
|
|
202
|
+
{
|
|
203
|
+
expiresInSeconds:
|
|
204
|
+
TelemetryAttributeService.CACHE_STALE_AFTER_MINUTES * 60,
|
|
205
|
+
},
|
|
206
|
+
);
|
|
207
|
+
} catch {
|
|
208
|
+
return;
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
private static buildAttributesStatement(data: {
|
|
40
213
|
projectId: ObjectID;
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
await this.deleteBy({
|
|
48
|
-
query: {
|
|
49
|
-
projectId,
|
|
50
|
-
telemetryType,
|
|
51
|
-
},
|
|
52
|
-
props: {
|
|
53
|
-
isRoot: true,
|
|
54
|
-
},
|
|
55
|
-
});
|
|
214
|
+
tableName: string;
|
|
215
|
+
attributesColumn: string;
|
|
216
|
+
timeColumn: string;
|
|
217
|
+
}): Statement {
|
|
218
|
+
const lookbackStartDate: Date =
|
|
219
|
+
TelemetryAttributeService.getLookbackStartDate();
|
|
56
220
|
|
|
57
|
-
const
|
|
221
|
+
const statement: Statement = SQL`
|
|
222
|
+
WITH filtered AS (
|
|
223
|
+
SELECT ${data.attributesColumn} AS attrs
|
|
224
|
+
FROM ${data.tableName}
|
|
225
|
+
WHERE projectId = ${{
|
|
226
|
+
type: TableColumnType.ObjectID,
|
|
227
|
+
value: data.projectId,
|
|
228
|
+
}}
|
|
229
|
+
AND ${data.attributesColumn} IS NOT NULL
|
|
230
|
+
AND ${data.attributesColumn} != ''
|
|
231
|
+
AND ${data.timeColumn} >= ${{
|
|
232
|
+
type: TableColumnType.Date,
|
|
233
|
+
value: lookbackStartDate,
|
|
234
|
+
}}
|
|
235
|
+
ORDER BY ${data.timeColumn} DESC
|
|
236
|
+
LIMIT ${{
|
|
237
|
+
type: TableColumnType.Number,
|
|
238
|
+
value: TelemetryAttributeService.ROW_SCAN_LIMIT,
|
|
239
|
+
}}
|
|
240
|
+
)
|
|
241
|
+
SELECT DISTINCT arrayJoin(JSONExtractKeys(attrs)) AS attribute
|
|
242
|
+
FROM filtered
|
|
243
|
+
ORDER BY attribute ASC
|
|
244
|
+
LIMIT ${{
|
|
245
|
+
type: TableColumnType.Number,
|
|
246
|
+
value: TelemetryAttributeService.ATTRIBUTES_LIMIT,
|
|
247
|
+
}}
|
|
248
|
+
`;
|
|
58
249
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
telemetryAttribute.attributes = attributes;
|
|
250
|
+
return statement;
|
|
251
|
+
}
|
|
62
252
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
253
|
+
private static async fetchAttributesFromDatabase(data: {
|
|
254
|
+
projectId: ObjectID;
|
|
255
|
+
source: TelemetrySource;
|
|
256
|
+
}): Promise<Array<string>> {
|
|
257
|
+
const statement: Statement =
|
|
258
|
+
TelemetryAttributeService.buildAttributesStatement({
|
|
259
|
+
projectId: data.projectId,
|
|
260
|
+
tableName: data.source.tableName,
|
|
261
|
+
attributesColumn: data.source.attributesColumn,
|
|
262
|
+
timeColumn: data.source.timeColumn,
|
|
263
|
+
});
|
|
264
|
+
|
|
265
|
+
const dbResult: Results = await data.source.service.executeQuery(statement);
|
|
266
|
+
const response: DbJSONResponse = await dbResult.json<{
|
|
267
|
+
data?: Array<JSONObject>;
|
|
268
|
+
}>();
|
|
269
|
+
|
|
270
|
+
const rows: Array<JSONObject> = response.data || [];
|
|
271
|
+
|
|
272
|
+
const attributeKeys: Array<string> = rows
|
|
273
|
+
.map((row: JSONObject) => {
|
|
274
|
+
const attribute: unknown = row["attribute"];
|
|
275
|
+
return typeof attribute === "string" ? attribute.trim() : null;
|
|
276
|
+
})
|
|
277
|
+
.filter((attribute: string | null): attribute is string => {
|
|
278
|
+
return Boolean(attribute);
|
|
279
|
+
});
|
|
280
|
+
|
|
281
|
+
return Array.from(new Set(attributeKeys));
|
|
69
282
|
}
|
|
70
283
|
}
|
|
71
284
|
|
|
@@ -1059,22 +1059,6 @@ export default class MonitorResourceUtil {
|
|
|
1059
1059
|
logger.error(err);
|
|
1060
1060
|
});
|
|
1061
1061
|
|
|
1062
|
-
// index attributes.
|
|
1063
|
-
TelemetryUtil.indexAttributes({
|
|
1064
|
-
attributes: [
|
|
1065
|
-
"monitorId",
|
|
1066
|
-
"projectId",
|
|
1067
|
-
"probeId",
|
|
1068
|
-
"browserType",
|
|
1069
|
-
"screenSizeType",
|
|
1070
|
-
"diskPath",
|
|
1071
|
-
],
|
|
1072
|
-
projectId: data.projectId,
|
|
1073
|
-
telemetryType: TelemetryType.Metric,
|
|
1074
|
-
}).catch((err: Error) => {
|
|
1075
|
-
logger.error(err);
|
|
1076
|
-
});
|
|
1077
|
-
|
|
1078
1062
|
// save monitor log.
|
|
1079
1063
|
const monitorLog: MonitorLog = new MonitorLog();
|
|
1080
1064
|
monitorLog.monitorId = data.monitorId;
|
|
@@ -1,10 +1,6 @@
|
|
|
1
1
|
import { JSONArray, JSONObject, JSONValue } from "../../../Types/JSON";
|
|
2
2
|
import ObjectID from "../../../Types/ObjectID";
|
|
3
|
-
import TelemetryType from "../../../Types/Telemetry/TelemetryType";
|
|
4
|
-
import GlobalCache from "../../Infrastructure/GlobalCache";
|
|
5
|
-
import TelemetryAttributeService from "../../Services/TelemetryAttributeService";
|
|
6
3
|
import CaptureSpan from "./CaptureSpan";
|
|
7
|
-
import logger from "../Logger";
|
|
8
4
|
import MetricType from "../../../Models/DatabaseModels/MetricType";
|
|
9
5
|
import MetricTypeService from "../../Services/MetricTypeService";
|
|
10
6
|
import TelemetryService from "../../../Models/DatabaseModels/TelemetryService";
|
|
@@ -127,63 +123,6 @@ export default class TelemetryUtil {
|
|
|
127
123
|
}
|
|
128
124
|
}
|
|
129
125
|
|
|
130
|
-
@CaptureSpan()
|
|
131
|
-
public static async indexAttributes(data: {
|
|
132
|
-
attributes: Array<string>;
|
|
133
|
-
projectId: ObjectID;
|
|
134
|
-
telemetryType: TelemetryType;
|
|
135
|
-
}): Promise<void> {
|
|
136
|
-
// index attributes
|
|
137
|
-
|
|
138
|
-
logger.debug("Indexing attributes");
|
|
139
|
-
logger.debug("data: " + JSON.stringify(data, null, 2));
|
|
140
|
-
|
|
141
|
-
const cacheKey: string =
|
|
142
|
-
data.projectId.toString() + "_" + data.telemetryType;
|
|
143
|
-
|
|
144
|
-
// get keys from cache
|
|
145
|
-
const cacheKeys: string[] =
|
|
146
|
-
(await GlobalCache.getStringArray("telemetryAttributesKeys", cacheKey)) ||
|
|
147
|
-
[];
|
|
148
|
-
|
|
149
|
-
let isKeysMissingInCache: boolean = false;
|
|
150
|
-
|
|
151
|
-
// check if keys are missing in cache
|
|
152
|
-
|
|
153
|
-
const attributeKeys: string[] = data.attributes;
|
|
154
|
-
|
|
155
|
-
for (const key of attributeKeys) {
|
|
156
|
-
if (!cacheKeys.includes(key)) {
|
|
157
|
-
isKeysMissingInCache = true;
|
|
158
|
-
break;
|
|
159
|
-
}
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
// merge keys and remove duplicates
|
|
163
|
-
if (isKeysMissingInCache) {
|
|
164
|
-
const dbKeys: string[] = await TelemetryAttributeService.fetchAttributes({
|
|
165
|
-
projectId: data.projectId,
|
|
166
|
-
telemetryType: data.telemetryType,
|
|
167
|
-
});
|
|
168
|
-
|
|
169
|
-
const mergedKeys: Array<string> = Array.from(
|
|
170
|
-
new Set([...dbKeys, ...attributeKeys, ...cacheKeys]),
|
|
171
|
-
);
|
|
172
|
-
|
|
173
|
-
await GlobalCache.setStringArray(
|
|
174
|
-
"telemetryAttributesKeys",
|
|
175
|
-
cacheKey,
|
|
176
|
-
mergedKeys,
|
|
177
|
-
);
|
|
178
|
-
|
|
179
|
-
await TelemetryAttributeService.refreshAttributes({
|
|
180
|
-
projectId: data.projectId,
|
|
181
|
-
telemetryType: data.telemetryType,
|
|
182
|
-
attributes: mergedKeys,
|
|
183
|
-
});
|
|
184
|
-
}
|
|
185
|
-
}
|
|
186
|
-
|
|
187
126
|
public static getAttributesForServiceIdAndServiceName(data: {
|
|
188
127
|
serviceId: ObjectID;
|
|
189
128
|
serviceName: string;
|
package/Types/Permission.ts
CHANGED
|
@@ -80,9 +80,6 @@ enum Permission {
|
|
|
80
80
|
EditTelemetryServiceMetrics = "EditTelemetryServiceMetrics",
|
|
81
81
|
ReadTelemetryServiceMetrics = "ReadTelemetryServiceMetrics",
|
|
82
82
|
|
|
83
|
-
// Telemetry Attributes
|
|
84
|
-
DeleteTelemetryAttributes = "DeleteTelemetryAttributes",
|
|
85
|
-
|
|
86
83
|
// Billing Permissions (Owner Permission)
|
|
87
84
|
ManageProjectBilling = "ManageProjectBilling",
|
|
88
85
|
|
|
@@ -30,6 +30,9 @@ export interface ComponentProps<T extends GenericObject> {
|
|
|
30
30
|
isModalLoading?: boolean;
|
|
31
31
|
onFilterRefreshClick?: undefined | (() => void);
|
|
32
32
|
filterData?: FilterData<T> | undefined;
|
|
33
|
+
onAdvancedFiltersToggle?:
|
|
34
|
+
| undefined
|
|
35
|
+
| ((showAdvancedFilters: boolean) => void);
|
|
33
36
|
}
|
|
34
37
|
|
|
35
38
|
type FilterComponentFunction = <T extends GenericObject>(
|
|
@@ -355,7 +358,7 @@ const FilterComponent: FilterComponentFunction = <T extends GenericObject>(
|
|
|
355
358
|
<div>
|
|
356
359
|
{showViewer && (
|
|
357
360
|
<div>
|
|
358
|
-
<div className="mt-5 mb-5 bg-gray-50 rounded
|
|
361
|
+
<div className="mt-5 mb-5 bg-gray-50 rounded-xl p-5 border-2 border-gray-100">
|
|
359
362
|
<div className="flex mt-1 mb-2">
|
|
360
363
|
<div className="flex-auto py-0.5 text-sm leading-5">
|
|
361
364
|
<span className="font-semibold">
|
|
@@ -442,6 +445,7 @@ const FilterComponent: FilterComponentFunction = <T extends GenericObject>(
|
|
|
442
445
|
onFilterChanged={(filterData: FilterData<T>) => {
|
|
443
446
|
setTempFilterDataForModal(filterData);
|
|
444
447
|
}}
|
|
448
|
+
onAdvancedFiltersToggle={props.onAdvancedFiltersToggle}
|
|
445
449
|
/>
|
|
446
450
|
</Modal>
|
|
447
451
|
)}
|
|
@@ -24,6 +24,9 @@ export interface ComponentProps<T extends GenericObject> {
|
|
|
24
24
|
isFilterLoading?: undefined | boolean;
|
|
25
25
|
filterError?: string | undefined;
|
|
26
26
|
onFilterRefreshClick?: undefined | (() => void);
|
|
27
|
+
onAdvancedFiltersToggle?:
|
|
28
|
+
| undefined
|
|
29
|
+
| ((showAdvancedFilters: boolean) => void);
|
|
27
30
|
}
|
|
28
31
|
|
|
29
32
|
type FiltersFormFunction = <T extends GenericObject>(
|
|
@@ -131,7 +134,11 @@ const FiltersForm: FiltersFormFunction = <T extends GenericObject>(
|
|
|
131
134
|
: "Show Advanced Filters"
|
|
132
135
|
}
|
|
133
136
|
onClick={() => {
|
|
134
|
-
setShowMoreFilters(
|
|
137
|
+
setShowMoreFilters((currentValue: boolean) => {
|
|
138
|
+
const newValue: boolean = !currentValue;
|
|
139
|
+
props.onAdvancedFiltersToggle?.(newValue);
|
|
140
|
+
return newValue;
|
|
141
|
+
});
|
|
135
142
|
}}
|
|
136
143
|
/>
|
|
137
144
|
)}
|
|
@@ -43,6 +43,9 @@ export interface ComponentProps<T extends GenericObject> {
|
|
|
43
43
|
onFilterRefreshClick?: undefined | (() => void);
|
|
44
44
|
onFilterModalClose?: (() => void) | undefined;
|
|
45
45
|
onFilterModalOpen?: (() => void) | undefined;
|
|
46
|
+
onAdvancedFiltersToggle?:
|
|
47
|
+
| undefined
|
|
48
|
+
| ((showAdvancedFilters: boolean) => void);
|
|
46
49
|
}
|
|
47
50
|
|
|
48
51
|
type ListFunction = <T extends GenericObject>(
|
|
@@ -118,6 +121,7 @@ const List: ListFunction = <T extends GenericObject>(
|
|
|
118
121
|
}}
|
|
119
122
|
singularLabel={props.singularLabel}
|
|
120
123
|
pluralLabel={props.pluralLabel}
|
|
124
|
+
onAdvancedFiltersToggle={props.onAdvancedFiltersToggle}
|
|
121
125
|
/>
|
|
122
126
|
</div>
|
|
123
127
|
<div className="">
|