@oneuptime/common 11.4.0 → 11.4.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.
Files changed (178) hide show
  1. package/Server/API/AIAgentTaskAPI.ts +10 -24
  2. package/Server/API/TelemetryAPI.ts +4 -3
  3. package/Server/Services/AIAgentTaskService.ts +62 -0
  4. package/Server/Services/AnalyticsDatabaseService.ts +27 -0
  5. package/Server/Services/LogAggregationService.ts +29 -11
  6. package/Server/Services/MetricService.ts +603 -13
  7. package/Server/Utils/AI/Sentinel/IncidentInvestigationRunner.ts +1 -1
  8. package/Server/Utils/AI/Sentinel/README.md +10 -0
  9. package/Server/Utils/Monitor/Criteria/APIRequestCriteria.ts +44 -0
  10. package/Server/Utils/Monitor/MonitorMetricUtil.ts +108 -2
  11. package/Tests/Server/Services/AIAgentTaskServiceClaim.test.ts +146 -0
  12. package/Tests/Server/Services/LogAggregationService.test.ts +22 -0
  13. package/Tests/Server/Services/MetricServiceAggregate.test.ts +194 -0
  14. package/Tests/Types/AI/AIAgentTaskStatus.test.ts +86 -0
  15. package/Tests/Types/BaseDatabase/AggregationIntervalUtil.test.ts +127 -0
  16. package/Tests/Types/BaseDatabase/DatabaseCommonInteractionPropsUtil.test.ts +152 -0
  17. package/Tests/Types/Trace/TraceRecordingRuleDefinition.test.ts +308 -0
  18. package/Tests/UI/Components/Dropdown.test.tsx +17 -0
  19. package/Tests/UI/Components/EntityDropdown.test.tsx +130 -0
  20. package/Tests/UI/Components/Modal.test.tsx +144 -2
  21. package/Tests/UI/Components/TelemetrySearchBar.test.tsx +90 -0
  22. package/Tests/UI/Utils/Theme.test.ts +161 -0
  23. package/Types/BaseDatabase/AggregateBy.ts +12 -0
  24. package/Types/Dashboard/DashboardComponentType.ts +1 -0
  25. package/Types/Dashboard/DashboardComponents/ComponentArgument.ts +1 -0
  26. package/Types/Dashboard/DashboardComponents/DashboardLogChartComponent.ts +19 -0
  27. package/Types/Dashboard/DashboardTemplates.ts +9 -1
  28. package/Types/Monitor/CriteriaFilter.ts +4 -0
  29. package/Types/Monitor/HttpPhaseTimings.ts +16 -0
  30. package/Types/Monitor/MonitorMetricType.ts +17 -0
  31. package/Types/Monitor/PingMonitor/PingMonitorResponse.ts +20 -0
  32. package/Types/Probe/ProbeMonitorResponse.ts +14 -0
  33. package/UI/Components/Charts/ChartLibrary/AreaChart/AreaChart.tsx +8 -5
  34. package/UI/Components/Charts/ChartLibrary/BarChart/BarChart.tsx +4 -1
  35. package/UI/Components/Charts/ChartLibrary/LineChart/LineChart.tsx +6 -3
  36. package/UI/Components/CodeBlock/CodeBlock.tsx +2 -1
  37. package/UI/Components/CodeEditor/CodeEditor.tsx +3 -0
  38. package/UI/Components/Divider/Divider.tsx +1 -1
  39. package/UI/Components/Dropdown/Dropdown.tsx +13 -4
  40. package/UI/Components/EntityDropdown/EntityDropdown.tsx +110 -2
  41. package/UI/Components/ErrorBoundary.tsx +2 -1
  42. package/UI/Components/EventItem/EventItem.tsx +2 -2
  43. package/UI/Components/GanttChart/Bar/Index.tsx +1 -1
  44. package/UI/Components/Graphs/UptimeBarTooltip.tsx +30 -23
  45. package/UI/Components/Header/Header.tsx +7 -0
  46. package/UI/Components/Header/HeaderIconDropdownButton.tsx +2 -0
  47. package/UI/Components/Label/Label.tsx +2 -2
  48. package/UI/Components/LogsViewer/components/LogsAnalyticsView.tsx +22 -10
  49. package/UI/Components/LogsViewer/components/LogsHistogram.tsx +9 -3
  50. package/UI/Components/Markdown.tsx/MarkdownEditor.tsx +8 -8
  51. package/UI/Components/Markdown.tsx/MarkdownViewer.tsx +44 -20
  52. package/UI/Components/Modal/ConfirmModal.tsx +1 -1
  53. package/UI/Components/Modal/Modal.tsx +213 -121
  54. package/UI/Components/Modal/ModalFooter.tsx +33 -22
  55. package/UI/Components/ModelTable/TableView.tsx +1 -1
  56. package/UI/Components/MonitorGraphs/UptimeBarDayModal.tsx +20 -12
  57. package/UI/Components/Pill/Pill.tsx +21 -13
  58. package/UI/Components/StatusBubble/StatusBubble.tsx +3 -3
  59. package/UI/Components/TelemetryViewer/TelemetryViewer.tsx +7 -1
  60. package/UI/Components/TelemetryViewer/components/TelemetryHistogram.tsx +9 -3
  61. package/UI/Components/TelemetryViewer/components/TelemetrySearchBar.tsx +62 -4
  62. package/UI/Components/Workflow/Component.tsx +53 -33
  63. package/UI/Components/Workflow/ComponentPortViewer.tsx +6 -6
  64. package/UI/Components/Workflow/ComponentReturnValueViewer.tsx +8 -8
  65. package/UI/Components/Workflow/ComponentsModal.tsx +16 -9
  66. package/UI/Components/Workflow/Workflow.tsx +13 -11
  67. package/UI/Utils/Theme.ts +140 -0
  68. package/Utils/Dashboard/Components/DashboardLogChartComponent.ts +104 -0
  69. package/Utils/Dashboard/Components/Index.ts +7 -0
  70. package/Utils/Monitor/MonitorMetricType.ts +70 -2
  71. package/build/dist/Server/API/AIAgentTaskAPI.js +8 -23
  72. package/build/dist/Server/API/AIAgentTaskAPI.js.map +1 -1
  73. package/build/dist/Server/API/TelemetryAPI.js.map +1 -1
  74. package/build/dist/Server/Services/AIAgentTaskService.js +59 -0
  75. package/build/dist/Server/Services/AIAgentTaskService.js.map +1 -1
  76. package/build/dist/Server/Services/AnalyticsDatabaseService.js +19 -0
  77. package/build/dist/Server/Services/AnalyticsDatabaseService.js.map +1 -1
  78. package/build/dist/Server/Services/LogAggregationService.js +21 -7
  79. package/build/dist/Server/Services/LogAggregationService.js.map +1 -1
  80. package/build/dist/Server/Services/MetricService.js +449 -7
  81. package/build/dist/Server/Services/MetricService.js.map +1 -1
  82. package/build/dist/Server/Utils/AI/Sentinel/IncidentInvestigationRunner.js +1 -1
  83. package/build/dist/Server/Utils/Monitor/Criteria/APIRequestCriteria.js +29 -0
  84. package/build/dist/Server/Utils/Monitor/Criteria/APIRequestCriteria.js.map +1 -1
  85. package/build/dist/Server/Utils/Monitor/MonitorMetricUtil.js +86 -2
  86. package/build/dist/Server/Utils/Monitor/MonitorMetricUtil.js.map +1 -1
  87. package/build/dist/Types/Dashboard/DashboardComponentType.js +1 -0
  88. package/build/dist/Types/Dashboard/DashboardComponentType.js.map +1 -1
  89. package/build/dist/Types/Dashboard/DashboardComponents/ComponentArgument.js +1 -0
  90. package/build/dist/Types/Dashboard/DashboardComponents/ComponentArgument.js.map +1 -1
  91. package/build/dist/Types/Dashboard/DashboardComponents/DashboardLogChartComponent.js +2 -0
  92. package/build/dist/Types/Dashboard/DashboardComponents/DashboardLogChartComponent.js.map +1 -0
  93. package/build/dist/Types/Dashboard/DashboardTemplates.js +9 -1
  94. package/build/dist/Types/Dashboard/DashboardTemplates.js.map +1 -1
  95. package/build/dist/Types/Monitor/CriteriaFilter.js +4 -0
  96. package/build/dist/Types/Monitor/CriteriaFilter.js.map +1 -1
  97. package/build/dist/Types/Monitor/HttpPhaseTimings.js +2 -0
  98. package/build/dist/Types/Monitor/HttpPhaseTimings.js.map +1 -0
  99. package/build/dist/Types/Monitor/MonitorMetricType.js +15 -0
  100. package/build/dist/Types/Monitor/MonitorMetricType.js.map +1 -1
  101. package/build/dist/Types/Monitor/PingMonitor/PingMonitorResponse.js +2 -0
  102. package/build/dist/Types/Monitor/PingMonitor/PingMonitorResponse.js.map +1 -0
  103. package/build/dist/UI/Components/Charts/ChartLibrary/AreaChart/AreaChart.js +7 -4
  104. package/build/dist/UI/Components/Charts/ChartLibrary/AreaChart/AreaChart.js.map +1 -1
  105. package/build/dist/UI/Components/Charts/ChartLibrary/BarChart/BarChart.js +4 -1
  106. package/build/dist/UI/Components/Charts/ChartLibrary/BarChart/BarChart.js.map +1 -1
  107. package/build/dist/UI/Components/Charts/ChartLibrary/LineChart/LineChart.js +6 -3
  108. package/build/dist/UI/Components/Charts/ChartLibrary/LineChart/LineChart.js.map +1 -1
  109. package/build/dist/UI/Components/CodeBlock/CodeBlock.js +1 -1
  110. package/build/dist/UI/Components/CodeBlock/CodeBlock.js.map +1 -1
  111. package/build/dist/UI/Components/CodeEditor/CodeEditor.js +3 -1
  112. package/build/dist/UI/Components/CodeEditor/CodeEditor.js.map +1 -1
  113. package/build/dist/UI/Components/Divider/Divider.js +1 -1
  114. package/build/dist/UI/Components/Divider/Divider.js.map +1 -1
  115. package/build/dist/UI/Components/Dropdown/Dropdown.js +10 -4
  116. package/build/dist/UI/Components/Dropdown/Dropdown.js.map +1 -1
  117. package/build/dist/UI/Components/EntityDropdown/EntityDropdown.js +76 -3
  118. package/build/dist/UI/Components/EntityDropdown/EntityDropdown.js.map +1 -1
  119. package/build/dist/UI/Components/ErrorBoundary.js +2 -1
  120. package/build/dist/UI/Components/ErrorBoundary.js.map +1 -1
  121. package/build/dist/UI/Components/EventItem/EventItem.js +2 -2
  122. package/build/dist/UI/Components/EventItem/EventItem.js.map +1 -1
  123. package/build/dist/UI/Components/GanttChart/Bar/Index.js +1 -1
  124. package/build/dist/UI/Components/GanttChart/Bar/Index.js.map +1 -1
  125. package/build/dist/UI/Components/Graphs/UptimeBarTooltip.js +29 -23
  126. package/build/dist/UI/Components/Graphs/UptimeBarTooltip.js.map +1 -1
  127. package/build/dist/UI/Components/Header/Header.js +1 -0
  128. package/build/dist/UI/Components/Header/Header.js.map +1 -1
  129. package/build/dist/UI/Components/Header/HeaderIconDropdownButton.js +1 -1
  130. package/build/dist/UI/Components/Header/HeaderIconDropdownButton.js.map +1 -1
  131. package/build/dist/UI/Components/Label/Label.js +2 -2
  132. package/build/dist/UI/Components/Label/Label.js.map +1 -1
  133. package/build/dist/UI/Components/LogsViewer/components/LogsAnalyticsView.js +20 -8
  134. package/build/dist/UI/Components/LogsViewer/components/LogsAnalyticsView.js.map +1 -1
  135. package/build/dist/UI/Components/LogsViewer/components/LogsHistogram.js +8 -2
  136. package/build/dist/UI/Components/LogsViewer/components/LogsHistogram.js.map +1 -1
  137. package/build/dist/UI/Components/Markdown.tsx/MarkdownEditor.js +8 -8
  138. package/build/dist/UI/Components/Markdown.tsx/MarkdownViewer.js +40 -20
  139. package/build/dist/UI/Components/Markdown.tsx/MarkdownViewer.js.map +1 -1
  140. package/build/dist/UI/Components/Modal/ConfirmModal.js +1 -1
  141. package/build/dist/UI/Components/Modal/ConfirmModal.js.map +1 -1
  142. package/build/dist/UI/Components/Modal/Modal.js +109 -51
  143. package/build/dist/UI/Components/Modal/Modal.js.map +1 -1
  144. package/build/dist/UI/Components/Modal/ModalFooter.js +13 -10
  145. package/build/dist/UI/Components/Modal/ModalFooter.js.map +1 -1
  146. package/build/dist/UI/Components/ModelTable/TableView.js +1 -1
  147. package/build/dist/UI/Components/ModelTable/TableView.js.map +1 -1
  148. package/build/dist/UI/Components/MonitorGraphs/UptimeBarDayModal.js +17 -12
  149. package/build/dist/UI/Components/MonitorGraphs/UptimeBarDayModal.js.map +1 -1
  150. package/build/dist/UI/Components/Pill/Pill.js +12 -13
  151. package/build/dist/UI/Components/Pill/Pill.js.map +1 -1
  152. package/build/dist/UI/Components/StatusBubble/StatusBubble.js +3 -3
  153. package/build/dist/UI/Components/StatusBubble/StatusBubble.js.map +1 -1
  154. package/build/dist/UI/Components/TelemetryViewer/TelemetryViewer.js +1 -1
  155. package/build/dist/UI/Components/TelemetryViewer/TelemetryViewer.js.map +1 -1
  156. package/build/dist/UI/Components/TelemetryViewer/components/TelemetryHistogram.js +8 -2
  157. package/build/dist/UI/Components/TelemetryViewer/components/TelemetryHistogram.js.map +1 -1
  158. package/build/dist/UI/Components/TelemetryViewer/components/TelemetrySearchBar.js +36 -6
  159. package/build/dist/UI/Components/TelemetryViewer/components/TelemetrySearchBar.js.map +1 -1
  160. package/build/dist/UI/Components/Workflow/Component.js +43 -33
  161. package/build/dist/UI/Components/Workflow/Component.js.map +1 -1
  162. package/build/dist/UI/Components/Workflow/ComponentPortViewer.js +6 -6
  163. package/build/dist/UI/Components/Workflow/ComponentPortViewer.js.map +1 -1
  164. package/build/dist/UI/Components/Workflow/ComponentReturnValueViewer.js +8 -8
  165. package/build/dist/UI/Components/Workflow/ComponentReturnValueViewer.js.map +1 -1
  166. package/build/dist/UI/Components/Workflow/ComponentsModal.js +15 -9
  167. package/build/dist/UI/Components/Workflow/ComponentsModal.js.map +1 -1
  168. package/build/dist/UI/Components/Workflow/Workflow.js +13 -11
  169. package/build/dist/UI/Components/Workflow/Workflow.js.map +1 -1
  170. package/build/dist/UI/Utils/Theme.js +106 -0
  171. package/build/dist/UI/Utils/Theme.js.map +1 -0
  172. package/build/dist/Utils/Dashboard/Components/DashboardLogChartComponent.js +92 -0
  173. package/build/dist/Utils/Dashboard/Components/DashboardLogChartComponent.js.map +1 -0
  174. package/build/dist/Utils/Dashboard/Components/Index.js +4 -0
  175. package/build/dist/Utils/Dashboard/Components/Index.js.map +1 -1
  176. package/build/dist/Utils/Monitor/MonitorMetricType.js +70 -3
  177. package/build/dist/Utils/Monitor/MonitorMetricType.js.map +1 -1
  178. package/package.json +1 -1
@@ -16,7 +16,6 @@ import { JSONObject } from "../../Types/JSON";
16
16
  import ObjectID from "../../Types/ObjectID";
17
17
  import OneUptimeDate from "../../Types/Date";
18
18
  import AIAgentTaskStatus from "../../Types/AI/AIAgentTaskStatus";
19
- import SortOrder from "../../Types/BaseDatabase/SortOrder";
20
19
  import PositiveNumber from "../../Types/PositiveNumber";
21
20
 
22
21
  export default class AIAgentTaskAPI extends BaseAPI<
@@ -27,8 +26,10 @@ export default class AIAgentTaskAPI extends BaseAPI<
27
26
  super(AIAgentTask, AIAgentTaskService);
28
27
 
29
28
  /*
30
- * Get the next pending (scheduled) task for processing
31
- * Validates aiAgentId and aiAgentKey before returning task
29
+ * Claim the next pending (scheduled) task for processing.
30
+ * Validates aiAgentId and aiAgentKey before claiming. The task is
31
+ * atomically transitioned Scheduled -> InProgress before it is
32
+ * returned, so concurrent workers can never receive the same task.
32
33
  */
33
34
  this.router.post(
34
35
  `${new this.entityType().getCrudApiPath()?.toString()}/get-pending-task`,
@@ -39,7 +40,7 @@ export default class AIAgentTaskAPI extends BaseAPI<
39
40
  /* Validate AI Agent credentials */
40
41
  const aiAgent: AIAgent | null = await this.validateAIAgent(data);
41
42
 
42
- if (!aiAgent) {
43
+ if (!aiAgent || !aiAgent.id) {
43
44
  return Response.sendErrorResponse(
44
45
  req,
45
46
  res,
@@ -47,25 +48,10 @@ export default class AIAgentTaskAPI extends BaseAPI<
47
48
  );
48
49
  }
49
50
 
50
- /* Fetch one scheduled task, sorted by createdAt (oldest first) */
51
- const task: AIAgentTask | null = await AIAgentTaskService.findOneBy({
52
- query: {
53
- status: AIAgentTaskStatus.Scheduled,
54
- },
55
- sort: {
56
- createdAt: SortOrder.Ascending,
57
- },
58
- select: {
59
- _id: true,
60
- projectId: true,
61
- taskType: true,
62
- metadata: true,
63
- createdAt: true,
64
- },
65
- props: {
66
- isRoot: true,
67
- },
68
- });
51
+ const task: AIAgentTask | null =
52
+ await AIAgentTaskService.claimNextScheduledTask({
53
+ aiAgentId: aiAgent.id,
54
+ });
69
55
 
70
56
  if (!task) {
71
57
  return Response.sendJsonObjectResponse(req, res, {
@@ -82,7 +68,7 @@ export default class AIAgentTaskAPI extends BaseAPI<
82
68
  metadata: task.metadata as JSONObject | undefined,
83
69
  createdAt: task.createdAt,
84
70
  },
85
- message: "Task fetched successfully",
71
+ message: "Task claimed successfully",
86
72
  });
87
73
  } catch (err) {
88
74
  next(err);
@@ -404,9 +404,10 @@ router.post(
404
404
  ? (body["spanIds"] as Array<string>)
405
405
  : undefined;
406
406
 
407
- const attributes: Record<string, string> | undefined = body["attributes"]
408
- ? (body["attributes"] as Record<string, string>)
409
- : undefined;
407
+ const attributes: Record<string, string | Array<string>> | undefined =
408
+ body["attributes"]
409
+ ? (body["attributes"] as Record<string, string | Array<string>>)
410
+ : undefined;
410
411
 
411
412
  const request: HistogramRequest = {
412
413
  projectId: databaseProps.tenantId,
@@ -11,6 +11,7 @@ import Semaphore, { SemaphoreMutex } from "../Infrastructure/Semaphore";
11
11
  import SortOrder from "../../Types/BaseDatabase/SortOrder";
12
12
  import logger from "../Utils/Logger";
13
13
  import OneUptimeDate from "../../Types/Date";
14
+ import AIAgentTaskStatus from "../../Types/AI/AIAgentTaskStatus";
14
15
 
15
16
  export class Service extends DatabaseService<Model> {
16
17
  public constructor() {
@@ -80,6 +81,67 @@ export class Service extends DatabaseService<Model> {
80
81
  return { createBy, carryForward: null };
81
82
  }
82
83
 
84
+ /*
85
+ * Atomically claim the oldest Scheduled task for a worker: the
86
+ * Scheduled -> InProgress transition is guarded on status, so when
87
+ * multiple workers poll concurrently only one claim succeeds
88
+ * (updateOneBy returns the number of rows changed — zero means another
89
+ * worker won the race, so we retry with the next candidate). The
90
+ * returned task is already InProgress and owned by the given agent.
91
+ */
92
+ @CaptureSpan()
93
+ public async claimNextScheduledTask(data: {
94
+ aiAgentId: ObjectID;
95
+ }): Promise<Model | null> {
96
+ const maxClaimAttempts: number = 5;
97
+
98
+ for (let attempt: number = 0; attempt < maxClaimAttempts; attempt++) {
99
+ const task: Model | null = await this.findOneBy({
100
+ query: {
101
+ status: AIAgentTaskStatus.Scheduled,
102
+ },
103
+ sort: {
104
+ createdAt: SortOrder.Ascending,
105
+ },
106
+ select: {
107
+ _id: true,
108
+ projectId: true,
109
+ taskType: true,
110
+ metadata: true,
111
+ createdAt: true,
112
+ },
113
+ props: {
114
+ isRoot: true,
115
+ },
116
+ });
117
+
118
+ if (!task || !task.id) {
119
+ return null;
120
+ }
121
+
122
+ const claimedCount: number = await this.updateOneBy({
123
+ query: {
124
+ _id: task.id.toString(),
125
+ status: AIAgentTaskStatus.Scheduled,
126
+ },
127
+ data: {
128
+ status: AIAgentTaskStatus.InProgress,
129
+ aiAgentId: data.aiAgentId,
130
+ startedAt: OneUptimeDate.getCurrentDate(),
131
+ },
132
+ props: {
133
+ isRoot: true,
134
+ },
135
+ });
136
+
137
+ if (claimedCount > 0) {
138
+ return task;
139
+ }
140
+ }
141
+
142
+ return null;
143
+ }
144
+
83
145
  @CaptureSpan()
84
146
  public async getExistingTaskNumberForProject(data: {
85
147
  projectId: ObjectID;
@@ -813,6 +813,19 @@ export default class AnalyticsDatabaseService<
813
813
  ? Object.keys(aggregateBy.groupBy)
814
814
  : [];
815
815
 
816
+ /*
817
+ * Attribute-key grouping returns the selected keys folded into a
818
+ * single `attributes` map column (see MetricService); carry it
819
+ * onto the aggregated rows so series splitters can read labels.
820
+ */
821
+ if (
822
+ aggregateBy.groupByAttributeKeys &&
823
+ aggregateBy.groupByAttributeKeys.length > 0 &&
824
+ !groupByColumnNames.includes("attributes")
825
+ ) {
826
+ groupByColumnNames.push("attributes");
827
+ }
828
+
816
829
  for (const item of items) {
817
830
  if (
818
831
  !(item as JSONObject)[
@@ -1171,6 +1184,20 @@ export default class AnalyticsDatabaseService<
1171
1184
  statement: Statement;
1172
1185
  columns: Array<string>;
1173
1186
  } {
1187
+ /*
1188
+ * Attribute-key grouping needs model-specific SQL over a map column
1189
+ * (MetricService builds it); reaching this generic path with keys
1190
+ * set would silently return ungrouped results.
1191
+ */
1192
+ if (
1193
+ aggregateBy.groupByAttributeKeys &&
1194
+ aggregateBy.groupByAttributeKeys.length > 0
1195
+ ) {
1196
+ throw new BadDataException(
1197
+ `groupByAttributeKeys is not supported for ${this.model.tableName}.`,
1198
+ );
1199
+ }
1200
+
1174
1201
  if (!this.database) {
1175
1202
  this.useDefaultDatabase();
1176
1203
  }
@@ -17,6 +17,9 @@ export interface HistogramBucket {
17
17
  count: number;
18
18
  }
19
19
 
20
+ export type LogAttributeFilterValue = string | Array<string>;
21
+ export type LogAttributeFilters = Record<string, LogAttributeFilterValue>;
22
+
20
23
  export interface HistogramRequest {
21
24
  projectId: ObjectID;
22
25
  startTime: Date;
@@ -28,7 +31,7 @@ export interface HistogramRequest {
28
31
  bodySearchText?: string | undefined;
29
32
  traceIds?: Array<string> | undefined;
30
33
  spanIds?: Array<string> | undefined;
31
- attributes?: Record<string, string> | undefined;
34
+ attributes?: LogAttributeFilters | undefined;
32
35
  }
33
36
 
34
37
  export interface FacetValue {
@@ -49,7 +52,7 @@ export interface FacetRequest {
49
52
  bodySearchText?: string | undefined;
50
53
  traceIds?: Array<string> | undefined;
51
54
  spanIds?: Array<string> | undefined;
52
- attributes?: Record<string, string> | undefined;
55
+ attributes?: LogAttributeFilters | undefined;
53
56
  }
54
57
 
55
58
  export type AnalyticsChartType = "timeseries" | "toplist" | "table";
@@ -834,15 +837,30 @@ export class LogAggregationService {
834
837
  * remember the exact casing is a poor experience. The user-supplied
835
838
  * key is validated above.
836
839
  */
837
- statement.append(
838
- SQL` AND arrayExists((k, v) -> lowerUTF8(k) = lowerUTF8(${{
839
- type: TableColumnType.Text,
840
- value: attrKey,
841
- }}) AND v = ${{
842
- type: TableColumnType.Text,
843
- value: attrValue,
844
- }}, mapKeys(attributes), mapValues(attributes))`,
845
- );
840
+ if (Array.isArray(attrValue)) {
841
+ if (attrValue.length === 0) {
842
+ continue;
843
+ }
844
+ statement.append(
845
+ SQL` AND arrayExists((k, v) -> lowerUTF8(k) = lowerUTF8(${{
846
+ type: TableColumnType.Text,
847
+ value: attrKey,
848
+ }}) AND v IN (${{
849
+ type: TableColumnType.Text,
850
+ value: new Includes(attrValue),
851
+ }}), mapKeys(attributes), mapValues(attributes))`,
852
+ );
853
+ } else {
854
+ statement.append(
855
+ SQL` AND arrayExists((k, v) -> lowerUTF8(k) = lowerUTF8(${{
856
+ type: TableColumnType.Text,
857
+ value: attrKey,
858
+ }}) AND v = ${{
859
+ type: TableColumnType.Text,
860
+ value: attrValue,
861
+ }}, mapKeys(attributes), mapValues(attributes))`,
862
+ );
863
+ }
846
864
  }
847
865
  }
848
866
  }