@oneuptime/common 10.0.28 → 10.0.30
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/DatabaseModels/Index.ts +2 -0
- package/Models/DatabaseModels/LogSavedView.ts +466 -0
- package/Server/API/TelemetryAPI.ts +146 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1772355000000-AddLogSavedView.ts +48 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1773344537755-MigrationName.ts +91 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +4 -0
- package/Server/Services/LogAggregationService.ts +387 -0
- package/Server/Services/LogSavedViewService.ts +109 -0
- package/Server/Types/Workflow/Components/BaseModel/OnTriggerBaseModel.ts +15 -0
- package/Server/Utils/Express.ts +1 -0
- package/Server/Utils/OpenAPI.ts +28 -0
- package/Server/Utils/StartServer.ts +20 -1
- package/UI/Components/LogsViewer/LogsViewer.tsx +204 -64
- package/UI/Components/LogsViewer/components/ColumnSelector.tsx +270 -0
- package/UI/Components/LogsViewer/components/LiveLogsToggle.tsx +3 -3
- package/UI/Components/LogsViewer/components/LogTimeRangePicker.tsx +2 -2
- package/UI/Components/LogsViewer/components/LogsAnalyticsView.tsx +699 -0
- package/UI/Components/LogsViewer/components/LogsFacetSidebar.tsx +46 -1
- package/UI/Components/LogsViewer/components/LogsFilterCard.tsx +3 -3
- package/UI/Components/LogsViewer/components/LogsTable.tsx +288 -103
- package/UI/Components/LogsViewer/components/LogsViewerToolbar.tsx +113 -11
- package/UI/Components/LogsViewer/components/SavedViewsDropdown.tsx +175 -0
- package/UI/Components/LogsViewer/types.ts +96 -0
- package/build/dist/Models/DatabaseModels/Index.js +2 -0
- package/build/dist/Models/DatabaseModels/Index.js.map +1 -1
- package/build/dist/Models/DatabaseModels/LogSavedView.js +496 -0
- package/build/dist/Models/DatabaseModels/LogSavedView.js.map +1 -0
- package/build/dist/Server/API/TelemetryAPI.js +88 -0
- package/build/dist/Server/API/TelemetryAPI.js.map +1 -1
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1772355000000-AddLogSavedView.js +44 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1772355000000-AddLogSavedView.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1773344537755-MigrationName.js +38 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1773344537755-MigrationName.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/LogAggregationService.js +249 -0
- package/build/dist/Server/Services/LogAggregationService.js.map +1 -1
- package/build/dist/Server/Services/LogSavedViewService.js +82 -0
- package/build/dist/Server/Services/LogSavedViewService.js.map +1 -0
- package/build/dist/Server/Types/Workflow/Components/BaseModel/OnTriggerBaseModel.js +15 -0
- package/build/dist/Server/Types/Workflow/Components/BaseModel/OnTriggerBaseModel.js.map +1 -1
- package/build/dist/Server/Utils/Express.js +1 -0
- package/build/dist/Server/Utils/Express.js.map +1 -1
- package/build/dist/Server/Utils/OpenAPI.js +24 -0
- package/build/dist/Server/Utils/OpenAPI.js.map +1 -1
- package/build/dist/Server/Utils/StartServer.js +17 -2
- package/build/dist/Server/Utils/StartServer.js.map +1 -1
- package/build/dist/UI/Components/LogsViewer/LogsViewer.js +77 -8
- package/build/dist/UI/Components/LogsViewer/LogsViewer.js.map +1 -1
- package/build/dist/UI/Components/LogsViewer/components/ColumnSelector.js +115 -0
- package/build/dist/UI/Components/LogsViewer/components/ColumnSelector.js.map +1 -0
- package/build/dist/UI/Components/LogsViewer/components/LiveLogsToggle.js +3 -3
- package/build/dist/UI/Components/LogsViewer/components/LiveLogsToggle.js.map +1 -1
- package/build/dist/UI/Components/LogsViewer/components/LogTimeRangePicker.js +2 -2
- package/build/dist/UI/Components/LogsViewer/components/LogTimeRangePicker.js.map +1 -1
- package/build/dist/UI/Components/LogsViewer/components/LogsAnalyticsView.js +379 -0
- package/build/dist/UI/Components/LogsViewer/components/LogsAnalyticsView.js.map +1 -0
- package/build/dist/UI/Components/LogsViewer/components/LogsFacetSidebar.js +27 -13
- package/build/dist/UI/Components/LogsViewer/components/LogsFacetSidebar.js.map +1 -1
- package/build/dist/UI/Components/LogsViewer/components/LogsFilterCard.js +3 -3
- package/build/dist/UI/Components/LogsViewer/components/LogsFilterCard.js.map +1 -1
- package/build/dist/UI/Components/LogsViewer/components/LogsTable.js +118 -49
- package/build/dist/UI/Components/LogsViewer/components/LogsTable.js.map +1 -1
- package/build/dist/UI/Components/LogsViewer/components/LogsViewerToolbar.js +35 -11
- package/build/dist/UI/Components/LogsViewer/components/LogsViewerToolbar.js.map +1 -1
- package/build/dist/UI/Components/LogsViewer/components/SavedViewsDropdown.js +58 -0
- package/build/dist/UI/Components/LogsViewer/components/SavedViewsDropdown.js.map +1 -0
- package/build/dist/UI/Components/LogsViewer/types.js +60 -1
- package/build/dist/UI/Components/LogsViewer/types.js.map +1 -1
- package/package.json +2 -2
|
@@ -36,6 +36,7 @@ import IncidentTemplateOwnerTeam from "./IncidentTemplateOwnerTeam";
|
|
|
36
36
|
import IncidentTemplateOwnerUser from "./IncidentTemplateOwnerUser";
|
|
37
37
|
//Labels.
|
|
38
38
|
import Label from "./Label";
|
|
39
|
+
import LogSavedView from "./LogSavedView";
|
|
39
40
|
// Monitors
|
|
40
41
|
import Monitor from "./Monitor";
|
|
41
42
|
import MonitorCustomField from "./MonitorCustomField";
|
|
@@ -250,6 +251,7 @@ const AllModelTypes: Array<{
|
|
|
250
251
|
TeamComplianceSetting,
|
|
251
252
|
ApiKey,
|
|
252
253
|
Label,
|
|
254
|
+
LogSavedView,
|
|
253
255
|
ApiKeyPermission,
|
|
254
256
|
ProjectSmtpConfig,
|
|
255
257
|
StatusPage,
|
|
@@ -0,0 +1,466 @@
|
|
|
1
|
+
import Project from "./Project";
|
|
2
|
+
import User from "./User";
|
|
3
|
+
import Log from "../AnalyticsModels/Log";
|
|
4
|
+
import BaseModel from "./DatabaseBaseModel/DatabaseBaseModel";
|
|
5
|
+
import Route from "../../Types/API/Route";
|
|
6
|
+
import SortOrder from "../../Types/BaseDatabase/SortOrder";
|
|
7
|
+
import Query from "../../Types/BaseDatabase/Query";
|
|
8
|
+
import ColumnAccessControl from "../../Types/Database/AccessControl/ColumnAccessControl";
|
|
9
|
+
import TableAccessControl from "../../Types/Database/AccessControl/TableAccessControl";
|
|
10
|
+
import TableBillingAccessControl from "../../Types/Database/AccessControl/TableBillingAccessControl";
|
|
11
|
+
import ColumnLength from "../../Types/Database/ColumnLength";
|
|
12
|
+
import ColumnType from "../../Types/Database/ColumnType";
|
|
13
|
+
import CrudApiEndpoint from "../../Types/Database/CrudApiEndpoint";
|
|
14
|
+
import EnableDocumentation from "../../Types/Database/EnableDocumentation";
|
|
15
|
+
import TableColumn from "../../Types/Database/TableColumn";
|
|
16
|
+
import TableColumnType from "../../Types/Database/TableColumnType";
|
|
17
|
+
import TableMetadata from "../../Types/Database/TableMetadata";
|
|
18
|
+
import TenantColumn from "../../Types/Database/TenantColumn";
|
|
19
|
+
import IconProp from "../../Types/Icon/IconProp";
|
|
20
|
+
import ObjectID from "../../Types/ObjectID";
|
|
21
|
+
import Permission from "../../Types/Permission";
|
|
22
|
+
import { PlanType } from "../../Types/Billing/SubscriptionPlan";
|
|
23
|
+
import { Column, Entity, Index, JoinColumn, ManyToOne } from "typeorm";
|
|
24
|
+
|
|
25
|
+
@EnableDocumentation()
|
|
26
|
+
@TableBillingAccessControl({
|
|
27
|
+
create: PlanType.Free,
|
|
28
|
+
read: PlanType.Free,
|
|
29
|
+
update: PlanType.Free,
|
|
30
|
+
delete: PlanType.Free,
|
|
31
|
+
})
|
|
32
|
+
@TenantColumn("projectId")
|
|
33
|
+
@CrudApiEndpoint(new Route("/log-saved-view"))
|
|
34
|
+
@Entity({
|
|
35
|
+
name: "LogSavedView",
|
|
36
|
+
})
|
|
37
|
+
@TableMetadata({
|
|
38
|
+
tableName: "LogSavedView",
|
|
39
|
+
singularName: "Log Saved View",
|
|
40
|
+
pluralName: "Log Saved Views",
|
|
41
|
+
icon: IconProp.Window,
|
|
42
|
+
tableDescription:
|
|
43
|
+
"Save and reuse log explorer views, including the current filters, columns, sorting, and page size.",
|
|
44
|
+
})
|
|
45
|
+
@TableAccessControl({
|
|
46
|
+
create: [
|
|
47
|
+
Permission.ProjectOwner,
|
|
48
|
+
Permission.ProjectAdmin,
|
|
49
|
+
Permission.ProjectMember,
|
|
50
|
+
],
|
|
51
|
+
read: [
|
|
52
|
+
Permission.ProjectOwner,
|
|
53
|
+
Permission.ProjectAdmin,
|
|
54
|
+
Permission.ProjectMember,
|
|
55
|
+
Permission.ReadAllProjectResources,
|
|
56
|
+
],
|
|
57
|
+
delete: [
|
|
58
|
+
Permission.ProjectOwner,
|
|
59
|
+
Permission.ProjectAdmin,
|
|
60
|
+
Permission.ProjectMember,
|
|
61
|
+
],
|
|
62
|
+
update: [
|
|
63
|
+
Permission.ProjectOwner,
|
|
64
|
+
Permission.ProjectAdmin,
|
|
65
|
+
Permission.ProjectMember,
|
|
66
|
+
],
|
|
67
|
+
})
|
|
68
|
+
export default class LogSavedView extends BaseModel {
|
|
69
|
+
@ColumnAccessControl({
|
|
70
|
+
create: [
|
|
71
|
+
Permission.ProjectOwner,
|
|
72
|
+
Permission.ProjectAdmin,
|
|
73
|
+
Permission.ProjectMember,
|
|
74
|
+
],
|
|
75
|
+
read: [
|
|
76
|
+
Permission.ProjectOwner,
|
|
77
|
+
Permission.ProjectAdmin,
|
|
78
|
+
Permission.ProjectMember,
|
|
79
|
+
Permission.ReadAllProjectResources,
|
|
80
|
+
],
|
|
81
|
+
update: [],
|
|
82
|
+
})
|
|
83
|
+
@TableColumn({
|
|
84
|
+
manyToOneRelationColumn: "projectId",
|
|
85
|
+
type: TableColumnType.Entity,
|
|
86
|
+
modelType: Project,
|
|
87
|
+
title: "Project",
|
|
88
|
+
description: "Relation to the project this saved log view belongs to.",
|
|
89
|
+
})
|
|
90
|
+
@ManyToOne(
|
|
91
|
+
() => {
|
|
92
|
+
return Project;
|
|
93
|
+
},
|
|
94
|
+
{
|
|
95
|
+
eager: false,
|
|
96
|
+
nullable: true,
|
|
97
|
+
onDelete: "CASCADE",
|
|
98
|
+
orphanedRowAction: "nullify",
|
|
99
|
+
},
|
|
100
|
+
)
|
|
101
|
+
@JoinColumn({ name: "projectId" })
|
|
102
|
+
public project?: Project = undefined;
|
|
103
|
+
|
|
104
|
+
@ColumnAccessControl({
|
|
105
|
+
create: [
|
|
106
|
+
Permission.ProjectOwner,
|
|
107
|
+
Permission.ProjectAdmin,
|
|
108
|
+
Permission.ProjectMember,
|
|
109
|
+
],
|
|
110
|
+
read: [
|
|
111
|
+
Permission.ProjectOwner,
|
|
112
|
+
Permission.ProjectAdmin,
|
|
113
|
+
Permission.ProjectMember,
|
|
114
|
+
Permission.ReadAllProjectResources,
|
|
115
|
+
],
|
|
116
|
+
update: [],
|
|
117
|
+
})
|
|
118
|
+
@Index()
|
|
119
|
+
@TableColumn({
|
|
120
|
+
type: TableColumnType.ObjectID,
|
|
121
|
+
required: true,
|
|
122
|
+
canReadOnRelationQuery: true,
|
|
123
|
+
title: "Project ID",
|
|
124
|
+
description: "ID of the project this saved log view belongs to.",
|
|
125
|
+
})
|
|
126
|
+
@Column({
|
|
127
|
+
type: ColumnType.ObjectID,
|
|
128
|
+
nullable: false,
|
|
129
|
+
transformer: ObjectID.getDatabaseTransformer(),
|
|
130
|
+
})
|
|
131
|
+
public projectId?: ObjectID = undefined;
|
|
132
|
+
|
|
133
|
+
@ColumnAccessControl({
|
|
134
|
+
create: [
|
|
135
|
+
Permission.ProjectOwner,
|
|
136
|
+
Permission.ProjectAdmin,
|
|
137
|
+
Permission.ProjectMember,
|
|
138
|
+
],
|
|
139
|
+
read: [
|
|
140
|
+
Permission.ProjectOwner,
|
|
141
|
+
Permission.ProjectAdmin,
|
|
142
|
+
Permission.ProjectMember,
|
|
143
|
+
Permission.ReadAllProjectResources,
|
|
144
|
+
],
|
|
145
|
+
update: [
|
|
146
|
+
Permission.ProjectOwner,
|
|
147
|
+
Permission.ProjectAdmin,
|
|
148
|
+
Permission.ProjectMember,
|
|
149
|
+
],
|
|
150
|
+
})
|
|
151
|
+
@TableColumn({
|
|
152
|
+
required: true,
|
|
153
|
+
type: TableColumnType.Name,
|
|
154
|
+
canReadOnRelationQuery: true,
|
|
155
|
+
title: "Name",
|
|
156
|
+
description: "Friendly name for this saved log view.",
|
|
157
|
+
})
|
|
158
|
+
@Column({
|
|
159
|
+
nullable: false,
|
|
160
|
+
type: ColumnType.Name,
|
|
161
|
+
length: ColumnLength.Name,
|
|
162
|
+
})
|
|
163
|
+
public name?: string = undefined;
|
|
164
|
+
|
|
165
|
+
@ColumnAccessControl({
|
|
166
|
+
create: [],
|
|
167
|
+
read: [
|
|
168
|
+
Permission.ProjectOwner,
|
|
169
|
+
Permission.ProjectAdmin,
|
|
170
|
+
Permission.ProjectMember,
|
|
171
|
+
Permission.ReadAllProjectResources,
|
|
172
|
+
],
|
|
173
|
+
update: [],
|
|
174
|
+
})
|
|
175
|
+
@TableColumn({
|
|
176
|
+
manyToOneRelationColumn: "createdByUserId",
|
|
177
|
+
type: TableColumnType.Entity,
|
|
178
|
+
modelType: User,
|
|
179
|
+
title: "Created By User",
|
|
180
|
+
description: "Relation to the user who created this saved log view.",
|
|
181
|
+
})
|
|
182
|
+
@ManyToOne(
|
|
183
|
+
() => {
|
|
184
|
+
return User;
|
|
185
|
+
},
|
|
186
|
+
{
|
|
187
|
+
eager: false,
|
|
188
|
+
nullable: true,
|
|
189
|
+
onDelete: "SET NULL",
|
|
190
|
+
orphanedRowAction: "nullify",
|
|
191
|
+
},
|
|
192
|
+
)
|
|
193
|
+
@JoinColumn({ name: "createdByUserId" })
|
|
194
|
+
public createdByUser?: User = undefined;
|
|
195
|
+
|
|
196
|
+
@ColumnAccessControl({
|
|
197
|
+
create: [],
|
|
198
|
+
read: [
|
|
199
|
+
Permission.ProjectOwner,
|
|
200
|
+
Permission.ProjectAdmin,
|
|
201
|
+
Permission.ProjectMember,
|
|
202
|
+
Permission.ReadAllProjectResources,
|
|
203
|
+
],
|
|
204
|
+
update: [],
|
|
205
|
+
})
|
|
206
|
+
@TableColumn({
|
|
207
|
+
type: TableColumnType.ObjectID,
|
|
208
|
+
title: "Created By User ID",
|
|
209
|
+
description: "ID of the user who created this saved log view.",
|
|
210
|
+
})
|
|
211
|
+
@Column({
|
|
212
|
+
type: ColumnType.ObjectID,
|
|
213
|
+
nullable: true,
|
|
214
|
+
transformer: ObjectID.getDatabaseTransformer(),
|
|
215
|
+
})
|
|
216
|
+
public createdByUserId?: ObjectID = undefined;
|
|
217
|
+
|
|
218
|
+
@ColumnAccessControl({
|
|
219
|
+
create: [],
|
|
220
|
+
read: [
|
|
221
|
+
Permission.ProjectOwner,
|
|
222
|
+
Permission.ProjectAdmin,
|
|
223
|
+
Permission.ProjectMember,
|
|
224
|
+
Permission.ReadAllProjectResources,
|
|
225
|
+
],
|
|
226
|
+
update: [],
|
|
227
|
+
})
|
|
228
|
+
@TableColumn({
|
|
229
|
+
manyToOneRelationColumn: "deletedByUserId",
|
|
230
|
+
type: TableColumnType.Entity,
|
|
231
|
+
modelType: User,
|
|
232
|
+
title: "Deleted By User",
|
|
233
|
+
description: "Relation to the user who deleted this saved log view.",
|
|
234
|
+
})
|
|
235
|
+
@ManyToOne(
|
|
236
|
+
() => {
|
|
237
|
+
return User;
|
|
238
|
+
},
|
|
239
|
+
{
|
|
240
|
+
eager: false,
|
|
241
|
+
nullable: true,
|
|
242
|
+
onDelete: "SET NULL",
|
|
243
|
+
orphanedRowAction: "nullify",
|
|
244
|
+
},
|
|
245
|
+
)
|
|
246
|
+
@JoinColumn({ name: "deletedByUserId" })
|
|
247
|
+
public deletedByUser?: User = undefined;
|
|
248
|
+
|
|
249
|
+
@ColumnAccessControl({
|
|
250
|
+
create: [],
|
|
251
|
+
read: [
|
|
252
|
+
Permission.ProjectOwner,
|
|
253
|
+
Permission.ProjectAdmin,
|
|
254
|
+
Permission.ProjectMember,
|
|
255
|
+
Permission.ReadAllProjectResources,
|
|
256
|
+
],
|
|
257
|
+
update: [],
|
|
258
|
+
})
|
|
259
|
+
@TableColumn({
|
|
260
|
+
type: TableColumnType.ObjectID,
|
|
261
|
+
title: "Deleted By User ID",
|
|
262
|
+
description: "ID of the user who deleted this saved log view.",
|
|
263
|
+
})
|
|
264
|
+
@Column({
|
|
265
|
+
type: ColumnType.ObjectID,
|
|
266
|
+
nullable: true,
|
|
267
|
+
transformer: ObjectID.getDatabaseTransformer(),
|
|
268
|
+
})
|
|
269
|
+
public deletedByUserId?: ObjectID = undefined;
|
|
270
|
+
|
|
271
|
+
@ColumnAccessControl({
|
|
272
|
+
create: [
|
|
273
|
+
Permission.ProjectOwner,
|
|
274
|
+
Permission.ProjectAdmin,
|
|
275
|
+
Permission.ProjectMember,
|
|
276
|
+
],
|
|
277
|
+
read: [
|
|
278
|
+
Permission.ProjectOwner,
|
|
279
|
+
Permission.ProjectAdmin,
|
|
280
|
+
Permission.ProjectMember,
|
|
281
|
+
Permission.ReadAllProjectResources,
|
|
282
|
+
],
|
|
283
|
+
update: [
|
|
284
|
+
Permission.ProjectOwner,
|
|
285
|
+
Permission.ProjectAdmin,
|
|
286
|
+
Permission.ProjectMember,
|
|
287
|
+
],
|
|
288
|
+
})
|
|
289
|
+
@TableColumn({
|
|
290
|
+
title: "Query",
|
|
291
|
+
required: true,
|
|
292
|
+
type: TableColumnType.JSON,
|
|
293
|
+
canReadOnRelationQuery: true,
|
|
294
|
+
description: "Serialized log query for this saved view.",
|
|
295
|
+
})
|
|
296
|
+
@Column({
|
|
297
|
+
type: ColumnType.JSON,
|
|
298
|
+
nullable: false,
|
|
299
|
+
})
|
|
300
|
+
public query?: Query<Log> = undefined;
|
|
301
|
+
|
|
302
|
+
@ColumnAccessControl({
|
|
303
|
+
create: [
|
|
304
|
+
Permission.ProjectOwner,
|
|
305
|
+
Permission.ProjectAdmin,
|
|
306
|
+
Permission.ProjectMember,
|
|
307
|
+
],
|
|
308
|
+
read: [
|
|
309
|
+
Permission.ProjectOwner,
|
|
310
|
+
Permission.ProjectAdmin,
|
|
311
|
+
Permission.ProjectMember,
|
|
312
|
+
Permission.ReadAllProjectResources,
|
|
313
|
+
],
|
|
314
|
+
update: [
|
|
315
|
+
Permission.ProjectOwner,
|
|
316
|
+
Permission.ProjectAdmin,
|
|
317
|
+
Permission.ProjectMember,
|
|
318
|
+
],
|
|
319
|
+
})
|
|
320
|
+
@TableColumn({
|
|
321
|
+
title: "Columns",
|
|
322
|
+
required: true,
|
|
323
|
+
type: TableColumnType.JSON,
|
|
324
|
+
canReadOnRelationQuery: true,
|
|
325
|
+
description: "Selected log table columns for this saved view.",
|
|
326
|
+
})
|
|
327
|
+
@Column({
|
|
328
|
+
type: ColumnType.JSON,
|
|
329
|
+
nullable: false,
|
|
330
|
+
default: () => {
|
|
331
|
+
return "'[]'";
|
|
332
|
+
},
|
|
333
|
+
})
|
|
334
|
+
public columns?: Array<string> = undefined;
|
|
335
|
+
|
|
336
|
+
@ColumnAccessControl({
|
|
337
|
+
create: [
|
|
338
|
+
Permission.ProjectOwner,
|
|
339
|
+
Permission.ProjectAdmin,
|
|
340
|
+
Permission.ProjectMember,
|
|
341
|
+
],
|
|
342
|
+
read: [
|
|
343
|
+
Permission.ProjectOwner,
|
|
344
|
+
Permission.ProjectAdmin,
|
|
345
|
+
Permission.ProjectMember,
|
|
346
|
+
Permission.ReadAllProjectResources,
|
|
347
|
+
],
|
|
348
|
+
update: [
|
|
349
|
+
Permission.ProjectOwner,
|
|
350
|
+
Permission.ProjectAdmin,
|
|
351
|
+
Permission.ProjectMember,
|
|
352
|
+
],
|
|
353
|
+
})
|
|
354
|
+
@TableColumn({
|
|
355
|
+
required: false,
|
|
356
|
+
type: TableColumnType.ShortText,
|
|
357
|
+
canReadOnRelationQuery: true,
|
|
358
|
+
title: "Sort Field",
|
|
359
|
+
description: "Active sort field for this saved log view.",
|
|
360
|
+
})
|
|
361
|
+
@Column({
|
|
362
|
+
nullable: true,
|
|
363
|
+
type: ColumnType.ShortText,
|
|
364
|
+
length: ColumnLength.ShortText,
|
|
365
|
+
})
|
|
366
|
+
public sortField?: string = undefined;
|
|
367
|
+
|
|
368
|
+
@ColumnAccessControl({
|
|
369
|
+
create: [
|
|
370
|
+
Permission.ProjectOwner,
|
|
371
|
+
Permission.ProjectAdmin,
|
|
372
|
+
Permission.ProjectMember,
|
|
373
|
+
],
|
|
374
|
+
read: [
|
|
375
|
+
Permission.ProjectOwner,
|
|
376
|
+
Permission.ProjectAdmin,
|
|
377
|
+
Permission.ProjectMember,
|
|
378
|
+
Permission.ReadAllProjectResources,
|
|
379
|
+
],
|
|
380
|
+
update: [
|
|
381
|
+
Permission.ProjectOwner,
|
|
382
|
+
Permission.ProjectAdmin,
|
|
383
|
+
Permission.ProjectMember,
|
|
384
|
+
],
|
|
385
|
+
})
|
|
386
|
+
@TableColumn({
|
|
387
|
+
required: false,
|
|
388
|
+
type: TableColumnType.ShortText,
|
|
389
|
+
canReadOnRelationQuery: true,
|
|
390
|
+
title: "Sort Order",
|
|
391
|
+
description: "Sort order for this saved log view.",
|
|
392
|
+
})
|
|
393
|
+
@Column({
|
|
394
|
+
nullable: true,
|
|
395
|
+
type: ColumnType.ShortText,
|
|
396
|
+
length: ColumnLength.ShortText,
|
|
397
|
+
})
|
|
398
|
+
public sortOrder?: SortOrder = undefined;
|
|
399
|
+
|
|
400
|
+
@ColumnAccessControl({
|
|
401
|
+
create: [
|
|
402
|
+
Permission.ProjectOwner,
|
|
403
|
+
Permission.ProjectAdmin,
|
|
404
|
+
Permission.ProjectMember,
|
|
405
|
+
],
|
|
406
|
+
read: [
|
|
407
|
+
Permission.ProjectOwner,
|
|
408
|
+
Permission.ProjectAdmin,
|
|
409
|
+
Permission.ProjectMember,
|
|
410
|
+
Permission.ReadAllProjectResources,
|
|
411
|
+
],
|
|
412
|
+
update: [
|
|
413
|
+
Permission.ProjectOwner,
|
|
414
|
+
Permission.ProjectAdmin,
|
|
415
|
+
Permission.ProjectMember,
|
|
416
|
+
],
|
|
417
|
+
})
|
|
418
|
+
@TableColumn({
|
|
419
|
+
title: "Page Size",
|
|
420
|
+
required: true,
|
|
421
|
+
type: TableColumnType.Number,
|
|
422
|
+
canReadOnRelationQuery: true,
|
|
423
|
+
description: "Number of logs per page for this saved view.",
|
|
424
|
+
defaultValue: 100,
|
|
425
|
+
})
|
|
426
|
+
@Column({
|
|
427
|
+
type: ColumnType.Number,
|
|
428
|
+
nullable: false,
|
|
429
|
+
default: 100,
|
|
430
|
+
})
|
|
431
|
+
public pageSize?: number = undefined;
|
|
432
|
+
|
|
433
|
+
@ColumnAccessControl({
|
|
434
|
+
create: [
|
|
435
|
+
Permission.ProjectOwner,
|
|
436
|
+
Permission.ProjectAdmin,
|
|
437
|
+
Permission.ProjectMember,
|
|
438
|
+
],
|
|
439
|
+
read: [
|
|
440
|
+
Permission.ProjectOwner,
|
|
441
|
+
Permission.ProjectAdmin,
|
|
442
|
+
Permission.ProjectMember,
|
|
443
|
+
Permission.ReadAllProjectResources,
|
|
444
|
+
],
|
|
445
|
+
update: [
|
|
446
|
+
Permission.ProjectOwner,
|
|
447
|
+
Permission.ProjectAdmin,
|
|
448
|
+
Permission.ProjectMember,
|
|
449
|
+
],
|
|
450
|
+
})
|
|
451
|
+
@Index()
|
|
452
|
+
@TableColumn({
|
|
453
|
+
required: true,
|
|
454
|
+
type: TableColumnType.Boolean,
|
|
455
|
+
canReadOnRelationQuery: true,
|
|
456
|
+
title: "Is Default",
|
|
457
|
+
description: "Whether this saved log view should be applied by default.",
|
|
458
|
+
defaultValue: false,
|
|
459
|
+
})
|
|
460
|
+
@Column({
|
|
461
|
+
nullable: false,
|
|
462
|
+
type: ColumnType.Boolean,
|
|
463
|
+
default: false,
|
|
464
|
+
})
|
|
465
|
+
public isDefault?: boolean = undefined;
|
|
466
|
+
}
|
|
@@ -16,6 +16,12 @@ import LogAggregationService, {
|
|
|
16
16
|
HistogramRequest,
|
|
17
17
|
FacetValue,
|
|
18
18
|
FacetRequest,
|
|
19
|
+
AnalyticsRequest,
|
|
20
|
+
AnalyticsChartType,
|
|
21
|
+
AnalyticsAggregation,
|
|
22
|
+
AnalyticsTimeseriesRow,
|
|
23
|
+
AnalyticsTopItem,
|
|
24
|
+
AnalyticsTableRow,
|
|
19
25
|
} from "../Services/LogAggregationService";
|
|
20
26
|
import ObjectID from "../../Types/ObjectID";
|
|
21
27
|
import OneUptimeDate from "../../Types/Date";
|
|
@@ -264,6 +270,146 @@ router.post(
|
|
|
264
270
|
},
|
|
265
271
|
);
|
|
266
272
|
|
|
273
|
+
// --- Log Analytics Endpoint ---
|
|
274
|
+
|
|
275
|
+
router.post(
|
|
276
|
+
"/telemetry/logs/analytics",
|
|
277
|
+
UserMiddleware.getUserMiddleware,
|
|
278
|
+
async (
|
|
279
|
+
req: ExpressRequest,
|
|
280
|
+
res: ExpressResponse,
|
|
281
|
+
next: NextFunction,
|
|
282
|
+
): Promise<void> => {
|
|
283
|
+
try {
|
|
284
|
+
const databaseProps: DatabaseCommonInteractionProps =
|
|
285
|
+
await CommonAPI.getDatabaseCommonInteractionProps(req);
|
|
286
|
+
|
|
287
|
+
if (!databaseProps?.tenantId) {
|
|
288
|
+
return Response.sendErrorResponse(
|
|
289
|
+
req,
|
|
290
|
+
res,
|
|
291
|
+
new BadDataException("Invalid Project ID"),
|
|
292
|
+
);
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
const body: JSONObject = req.body as JSONObject;
|
|
296
|
+
|
|
297
|
+
const chartType: AnalyticsChartType =
|
|
298
|
+
(body["chartType"] as AnalyticsChartType) || "timeseries";
|
|
299
|
+
|
|
300
|
+
if (!["timeseries", "toplist", "table"].includes(chartType)) {
|
|
301
|
+
return Response.sendErrorResponse(
|
|
302
|
+
req,
|
|
303
|
+
res,
|
|
304
|
+
new BadDataException("Invalid chartType"),
|
|
305
|
+
);
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
const aggregation: AnalyticsAggregation =
|
|
309
|
+
(body["aggregation"] as AnalyticsAggregation) || "count";
|
|
310
|
+
|
|
311
|
+
if (!["count", "unique"].includes(aggregation)) {
|
|
312
|
+
return Response.sendErrorResponse(
|
|
313
|
+
req,
|
|
314
|
+
res,
|
|
315
|
+
new BadDataException("Invalid aggregation"),
|
|
316
|
+
);
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
const startTime: Date = body["startTime"]
|
|
320
|
+
? OneUptimeDate.fromString(body["startTime"] as string)
|
|
321
|
+
: OneUptimeDate.addRemoveHours(OneUptimeDate.getCurrentDate(), -1);
|
|
322
|
+
|
|
323
|
+
const endTime: Date = body["endTime"]
|
|
324
|
+
? OneUptimeDate.fromString(body["endTime"] as string)
|
|
325
|
+
: OneUptimeDate.getCurrentDate();
|
|
326
|
+
|
|
327
|
+
const bucketSizeInMinutes: number =
|
|
328
|
+
(body["bucketSizeInMinutes"] as number) ||
|
|
329
|
+
computeDefaultBucketSize(startTime, endTime);
|
|
330
|
+
|
|
331
|
+
const serviceIds: Array<ObjectID> | undefined = body["serviceIds"]
|
|
332
|
+
? (body["serviceIds"] as Array<string>).map((id: string) => {
|
|
333
|
+
return new ObjectID(id);
|
|
334
|
+
})
|
|
335
|
+
: undefined;
|
|
336
|
+
|
|
337
|
+
const severityTexts: Array<string> | undefined = body["severityTexts"]
|
|
338
|
+
? (body["severityTexts"] as Array<string>)
|
|
339
|
+
: undefined;
|
|
340
|
+
|
|
341
|
+
const bodySearchText: string | undefined = body["bodySearchText"]
|
|
342
|
+
? (body["bodySearchText"] as string)
|
|
343
|
+
: undefined;
|
|
344
|
+
|
|
345
|
+
const traceIds: Array<string> | undefined = body["traceIds"]
|
|
346
|
+
? (body["traceIds"] as Array<string>)
|
|
347
|
+
: undefined;
|
|
348
|
+
|
|
349
|
+
const spanIds: Array<string> | undefined = body["spanIds"]
|
|
350
|
+
? (body["spanIds"] as Array<string>)
|
|
351
|
+
: undefined;
|
|
352
|
+
|
|
353
|
+
const groupBy: Array<string> | undefined = body["groupBy"]
|
|
354
|
+
? (body["groupBy"] as Array<string>)
|
|
355
|
+
: undefined;
|
|
356
|
+
|
|
357
|
+
const aggregationField: string | undefined = body["aggregationField"]
|
|
358
|
+
? (body["aggregationField"] as string)
|
|
359
|
+
: undefined;
|
|
360
|
+
|
|
361
|
+
const limit: number | undefined = body["limit"]
|
|
362
|
+
? (body["limit"] as number)
|
|
363
|
+
: undefined;
|
|
364
|
+
|
|
365
|
+
const request: AnalyticsRequest = {
|
|
366
|
+
projectId: databaseProps.tenantId,
|
|
367
|
+
startTime,
|
|
368
|
+
endTime,
|
|
369
|
+
bucketSizeInMinutes,
|
|
370
|
+
chartType,
|
|
371
|
+
groupBy,
|
|
372
|
+
aggregation,
|
|
373
|
+
aggregationField,
|
|
374
|
+
serviceIds,
|
|
375
|
+
severityTexts,
|
|
376
|
+
bodySearchText,
|
|
377
|
+
traceIds,
|
|
378
|
+
spanIds,
|
|
379
|
+
limit,
|
|
380
|
+
};
|
|
381
|
+
|
|
382
|
+
if (chartType === "timeseries") {
|
|
383
|
+
const data: Array<AnalyticsTimeseriesRow> =
|
|
384
|
+
await LogAggregationService.getAnalyticsTimeseries(request);
|
|
385
|
+
|
|
386
|
+
return Response.sendJsonObjectResponse(req, res, {
|
|
387
|
+
data: data as unknown as JSONObject,
|
|
388
|
+
});
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
if (chartType === "toplist") {
|
|
392
|
+
const data: Array<AnalyticsTopItem> =
|
|
393
|
+
await LogAggregationService.getAnalyticsTopList(request);
|
|
394
|
+
|
|
395
|
+
return Response.sendJsonObjectResponse(req, res, {
|
|
396
|
+
data: data as unknown as JSONObject,
|
|
397
|
+
});
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
// table
|
|
401
|
+
const data: Array<AnalyticsTableRow> =
|
|
402
|
+
await LogAggregationService.getAnalyticsTable(request);
|
|
403
|
+
|
|
404
|
+
return Response.sendJsonObjectResponse(req, res, {
|
|
405
|
+
data: data as unknown as JSONObject,
|
|
406
|
+
});
|
|
407
|
+
} catch (err: unknown) {
|
|
408
|
+
next(err);
|
|
409
|
+
}
|
|
410
|
+
},
|
|
411
|
+
);
|
|
412
|
+
|
|
267
413
|
// --- Helpers ---
|
|
268
414
|
|
|
269
415
|
function computeDefaultBucketSize(startTime: Date, endTime: Date): number {
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { MigrationInterface, QueryRunner } from "typeorm";
|
|
2
|
+
import CaptureSpan from "../../../Utils/Telemetry/CaptureSpan";
|
|
3
|
+
|
|
4
|
+
export class AddLogSavedView1772355000000 implements MigrationInterface {
|
|
5
|
+
public name = "AddLogSavedView1772355000000";
|
|
6
|
+
|
|
7
|
+
@CaptureSpan()
|
|
8
|
+
public async up(queryRunner: QueryRunner): Promise<void> {
|
|
9
|
+
await queryRunner.query(
|
|
10
|
+
`CREATE TABLE "LogSavedView" ("_id" uuid NOT NULL DEFAULT uuid_generate_v4(), "createdAt" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(), "updatedAt" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(), "deletedAt" TIMESTAMP WITH TIME ZONE, "version" integer NOT NULL, "projectId" uuid NOT NULL, "name" character varying(100) NOT NULL, "createdByUserId" uuid, "deletedByUserId" uuid, "query" jsonb NOT NULL, "columns" jsonb NOT NULL DEFAULT '[]', "sortField" character varying(100), "sortOrder" character varying(100), "pageSize" integer NOT NULL DEFAULT '100', "isDefault" boolean NOT NULL DEFAULT false, CONSTRAINT "PK_b1d3249a8cce9f7168bded6d55a" PRIMARY KEY ("_id"))`,
|
|
11
|
+
);
|
|
12
|
+
await queryRunner.query(
|
|
13
|
+
`CREATE INDEX "IDX_56e1d744839c4e59c50de300a9" ON "LogSavedView" ("projectId") `,
|
|
14
|
+
);
|
|
15
|
+
await queryRunner.query(
|
|
16
|
+
`CREATE INDEX "IDX_80241afbecf0a3749cc775f93f" ON "LogSavedView" ("isDefault") `,
|
|
17
|
+
);
|
|
18
|
+
await queryRunner.query(
|
|
19
|
+
`ALTER TABLE "LogSavedView" ADD CONSTRAINT "FK_56e1d744839c4e59c50de300a9d" FOREIGN KEY ("projectId") REFERENCES "Project"("_id") ON DELETE CASCADE ON UPDATE NO ACTION`,
|
|
20
|
+
);
|
|
21
|
+
await queryRunner.query(
|
|
22
|
+
`ALTER TABLE "LogSavedView" ADD CONSTRAINT "FK_fa55f4b8cb6e6ce31554b7b021f" FOREIGN KEY ("createdByUserId") REFERENCES "User"("_id") ON DELETE SET NULL ON UPDATE NO ACTION`,
|
|
23
|
+
);
|
|
24
|
+
await queryRunner.query(
|
|
25
|
+
`ALTER TABLE "LogSavedView" ADD CONSTRAINT "FK_8bd2b62c5f269dc8b2c74da0f27" FOREIGN KEY ("deletedByUserId") REFERENCES "User"("_id") ON DELETE SET NULL ON UPDATE NO ACTION`,
|
|
26
|
+
);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
@CaptureSpan()
|
|
30
|
+
public async down(queryRunner: QueryRunner): Promise<void> {
|
|
31
|
+
await queryRunner.query(
|
|
32
|
+
`ALTER TABLE "LogSavedView" DROP CONSTRAINT "FK_8bd2b62c5f269dc8b2c74da0f27"`,
|
|
33
|
+
);
|
|
34
|
+
await queryRunner.query(
|
|
35
|
+
`ALTER TABLE "LogSavedView" DROP CONSTRAINT "FK_fa55f4b8cb6e6ce31554b7b021f"`,
|
|
36
|
+
);
|
|
37
|
+
await queryRunner.query(
|
|
38
|
+
`ALTER TABLE "LogSavedView" DROP CONSTRAINT "FK_56e1d744839c4e59c50de300a9d"`,
|
|
39
|
+
);
|
|
40
|
+
await queryRunner.query(
|
|
41
|
+
`DROP INDEX "public"."IDX_80241afbecf0a3749cc775f93f"`,
|
|
42
|
+
);
|
|
43
|
+
await queryRunner.query(
|
|
44
|
+
`DROP INDEX "public"."IDX_56e1d744839c4e59c50de300a9"`,
|
|
45
|
+
);
|
|
46
|
+
await queryRunner.query(`DROP TABLE "LogSavedView"`);
|
|
47
|
+
}
|
|
48
|
+
}
|