@openchoreo/backstage-plugin-openchoreo-observability 1.1.0

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 (196) hide show
  1. package/CHANGELOG.md +5 -0
  2. package/README.md +22 -0
  3. package/dist/api/FinOpsAgentApi.esm.js +43 -0
  4. package/dist/api/FinOpsAgentApi.esm.js.map +1 -0
  5. package/dist/api/ObservabilityApi.esm.js +568 -0
  6. package/dist/api/ObservabilityApi.esm.js.map +1 -0
  7. package/dist/api/ObserverUrlCache.esm.js +59 -0
  8. package/dist/api/ObserverUrlCache.esm.js.map +1 -0
  9. package/dist/api/RCAAgentApi.esm.js +104 -0
  10. package/dist/api/RCAAgentApi.esm.js.map +1 -0
  11. package/dist/components/Alerts/AlertRow.esm.js +203 -0
  12. package/dist/components/Alerts/AlertRow.esm.js.map +1 -0
  13. package/dist/components/Alerts/AlertsActions.esm.js +77 -0
  14. package/dist/components/Alerts/AlertsActions.esm.js.map +1 -0
  15. package/dist/components/Alerts/AlertsFilter.esm.js +95 -0
  16. package/dist/components/Alerts/AlertsFilter.esm.js.map +1 -0
  17. package/dist/components/Alerts/AlertsTable.esm.js +63 -0
  18. package/dist/components/Alerts/AlertsTable.esm.js.map +1 -0
  19. package/dist/components/Alerts/ObservabilityAlertsPage.esm.js +251 -0
  20. package/dist/components/Alerts/ObservabilityAlertsPage.esm.js.map +1 -0
  21. package/dist/components/Alerts/types.esm.js +4 -0
  22. package/dist/components/Alerts/types.esm.js.map +1 -0
  23. package/dist/components/CostAnalysis/CostAnalysisPage.esm.js +141 -0
  24. package/dist/components/CostAnalysis/CostAnalysisPage.esm.js.map +1 -0
  25. package/dist/components/CostAnalysis/CostAnalysisReport.esm.js +128 -0
  26. package/dist/components/CostAnalysis/CostAnalysisReport.esm.js.map +1 -0
  27. package/dist/components/CostAnalysis/CostAnalysisReportView.esm.js +517 -0
  28. package/dist/components/CostAnalysis/CostAnalysisReportView.esm.js.map +1 -0
  29. package/dist/components/CostAnalysis/CostAnalysisTable.esm.js +149 -0
  30. package/dist/components/CostAnalysis/CostAnalysisTable.esm.js.map +1 -0
  31. package/dist/components/CostAnalysis/FinOpsApplyButton.esm.js +112 -0
  32. package/dist/components/CostAnalysis/FinOpsApplyButton.esm.js.map +1 -0
  33. package/dist/components/CostAnalysis/index.esm.js +2 -0
  34. package/dist/components/CostAnalysis/index.esm.js.map +1 -0
  35. package/dist/components/Incidents/IncidentRow.esm.js +258 -0
  36. package/dist/components/Incidents/IncidentRow.esm.js.map +1 -0
  37. package/dist/components/Incidents/IncidentsActions.esm.js +77 -0
  38. package/dist/components/Incidents/IncidentsActions.esm.js.map +1 -0
  39. package/dist/components/Incidents/IncidentsFilter.esm.js +144 -0
  40. package/dist/components/Incidents/IncidentsFilter.esm.js.map +1 -0
  41. package/dist/components/Incidents/IncidentsTable.esm.js +68 -0
  42. package/dist/components/Incidents/IncidentsTable.esm.js.map +1 -0
  43. package/dist/components/Incidents/ObservabilityProjectIncidentsPage.esm.js +283 -0
  44. package/dist/components/Incidents/ObservabilityProjectIncidentsPage.esm.js.map +1 -0
  45. package/dist/components/Incidents/types.esm.js +8 -0
  46. package/dist/components/Incidents/types.esm.js.map +1 -0
  47. package/dist/components/Metrics/ChartTooltip.esm.js +53 -0
  48. package/dist/components/Metrics/ChartTooltip.esm.js.map +1 -0
  49. package/dist/components/Metrics/HTTPMetricsSection.esm.js +109 -0
  50. package/dist/components/Metrics/HTTPMetricsSection.esm.js.map +1 -0
  51. package/dist/components/Metrics/MetricGraphByComponent.esm.js +99 -0
  52. package/dist/components/Metrics/MetricGraphByComponent.esm.js.map +1 -0
  53. package/dist/components/Metrics/MetricsActions.esm.js +30 -0
  54. package/dist/components/Metrics/MetricsActions.esm.js.map +1 -0
  55. package/dist/components/Metrics/MetricsFilters.esm.js +49 -0
  56. package/dist/components/Metrics/MetricsFilters.esm.js.map +1 -0
  57. package/dist/components/Metrics/ObservabilityMetricsPage.esm.js +196 -0
  58. package/dist/components/Metrics/ObservabilityMetricsPage.esm.js.map +1 -0
  59. package/dist/components/Metrics/styles.esm.js +55 -0
  60. package/dist/components/Metrics/styles.esm.js.map +1 -0
  61. package/dist/components/Metrics/utils.esm.js +221 -0
  62. package/dist/components/Metrics/utils.esm.js.map +1 -0
  63. package/dist/components/RCA/RCAActions.esm.js +42 -0
  64. package/dist/components/RCA/RCAActions.esm.js.map +1 -0
  65. package/dist/components/RCA/RCAFilters.esm.js +100 -0
  66. package/dist/components/RCA/RCAFilters.esm.js.map +1 -0
  67. package/dist/components/RCA/RCAPage.esm.js +137 -0
  68. package/dist/components/RCA/RCAPage.esm.js.map +1 -0
  69. package/dist/components/RCA/RCAReport/EntityLinkContext.esm.js +9 -0
  70. package/dist/components/RCA/RCAReport/EntityLinkContext.esm.js.map +1 -0
  71. package/dist/components/RCA/RCAReport/FormattedText.esm.js +94 -0
  72. package/dist/components/RCA/RCAReport/FormattedText.esm.js.map +1 -0
  73. package/dist/components/RCA/RCAReport/RCAReportView.esm.js +308 -0
  74. package/dist/components/RCA/RCAReport/RCAReportView.esm.js.map +1 -0
  75. package/dist/components/RCA/RCAReport/sections/AssessmentSection.esm.js +113 -0
  76. package/dist/components/RCA/RCAReport/sections/AssessmentSection.esm.js.map +1 -0
  77. package/dist/components/RCA/RCAReport/sections/ChatPanelSection.esm.js +272 -0
  78. package/dist/components/RCA/RCAReport/sections/ChatPanelSection.esm.js.map +1 -0
  79. package/dist/components/RCA/RCAReport/sections/ExcludedCausesSection.esm.js +48 -0
  80. package/dist/components/RCA/RCAReport/sections/ExcludedCausesSection.esm.js.map +1 -0
  81. package/dist/components/RCA/RCAReport/sections/IncidentOverviewSection.esm.js +205 -0
  82. package/dist/components/RCA/RCAReport/sections/IncidentOverviewSection.esm.js.map +1 -0
  83. package/dist/components/RCA/RCAReport/sections/InvestigationPathSection.esm.js +121 -0
  84. package/dist/components/RCA/RCAReport/sections/InvestigationPathSection.esm.js.map +1 -0
  85. package/dist/components/RCA/RCAReport/sections/PatchTabContent.esm.js +593 -0
  86. package/dist/components/RCA/RCAReport/sections/PatchTabContent.esm.js.map +1 -0
  87. package/dist/components/RCA/RCAReport/sections/QuickFixesPanelSection.esm.js +35 -0
  88. package/dist/components/RCA/RCAReport/sections/QuickFixesPanelSection.esm.js.map +1 -0
  89. package/dist/components/RCA/RCAReport/sections/RecommendationsSection.esm.js +54 -0
  90. package/dist/components/RCA/RCAReport/sections/RecommendationsSection.esm.js.map +1 -0
  91. package/dist/components/RCA/RCAReport/sections/RootCausesSection.esm.js +526 -0
  92. package/dist/components/RCA/RCAReport/sections/RootCausesSection.esm.js.map +1 -0
  93. package/dist/components/RCA/RCAReport/sections/SystemTimelineSection.esm.js +70 -0
  94. package/dist/components/RCA/RCAReport/sections/SystemTimelineSection.esm.js.map +1 -0
  95. package/dist/components/RCA/RCAReport/sections/VisibilityImprovementsSection.esm.js +54 -0
  96. package/dist/components/RCA/RCAReport/sections/VisibilityImprovementsSection.esm.js.map +1 -0
  97. package/dist/components/RCA/RCAReport/styles.esm.js +467 -0
  98. package/dist/components/RCA/RCAReport/styles.esm.js.map +1 -0
  99. package/dist/components/RCA/RCAReport.esm.js +109 -0
  100. package/dist/components/RCA/RCAReport.esm.js.map +1 -0
  101. package/dist/components/RCA/RCATable.esm.js +140 -0
  102. package/dist/components/RCA/RCATable.esm.js.map +1 -0
  103. package/dist/components/RuntimeLogs/LogEntry.esm.js +182 -0
  104. package/dist/components/RuntimeLogs/LogEntry.esm.js.map +1 -0
  105. package/dist/components/RuntimeLogs/LogsActions.esm.js +106 -0
  106. package/dist/components/RuntimeLogs/LogsActions.esm.js.map +1 -0
  107. package/dist/components/RuntimeLogs/LogsFilter.esm.js +200 -0
  108. package/dist/components/RuntimeLogs/LogsFilter.esm.js.map +1 -0
  109. package/dist/components/RuntimeLogs/LogsTable.esm.js +91 -0
  110. package/dist/components/RuntimeLogs/LogsTable.esm.js.map +1 -0
  111. package/dist/components/RuntimeLogs/ObservabilityProjectRuntimeLogsPage.esm.js +220 -0
  112. package/dist/components/RuntimeLogs/ObservabilityProjectRuntimeLogsPage.esm.js.map +1 -0
  113. package/dist/components/RuntimeLogs/ObservabilityRuntimeLogsPage.esm.js +222 -0
  114. package/dist/components/RuntimeLogs/ObservabilityRuntimeLogsPage.esm.js.map +1 -0
  115. package/dist/components/RuntimeLogs/styles.esm.js +256 -0
  116. package/dist/components/RuntimeLogs/styles.esm.js.map +1 -0
  117. package/dist/components/RuntimeLogs/types.esm.js +16 -0
  118. package/dist/components/RuntimeLogs/types.esm.js.map +1 -0
  119. package/dist/components/TimeRangeFilter/TimeRangeFilter.esm.js +280 -0
  120. package/dist/components/TimeRangeFilter/TimeRangeFilter.esm.js.map +1 -0
  121. package/dist/components/Traces/ObservabilityTracesPage.esm.js +165 -0
  122. package/dist/components/Traces/ObservabilityTracesPage.esm.js.map +1 -0
  123. package/dist/components/Traces/TracesActions.esm.js +37 -0
  124. package/dist/components/Traces/TracesActions.esm.js.map +1 -0
  125. package/dist/components/Traces/TracesFilters.esm.js +121 -0
  126. package/dist/components/Traces/TracesFilters.esm.js.map +1 -0
  127. package/dist/components/Traces/TracesTable.esm.js +137 -0
  128. package/dist/components/Traces/TracesTable.esm.js.map +1 -0
  129. package/dist/components/Traces/WaterfallView.esm.js +567 -0
  130. package/dist/components/Traces/WaterfallView.esm.js.map +1 -0
  131. package/dist/components/Traces/styles.esm.js +198 -0
  132. package/dist/components/Traces/styles.esm.js.map +1 -0
  133. package/dist/components/Traces/utils.esm.js +19 -0
  134. package/dist/components/Traces/utils.esm.js.map +1 -0
  135. package/dist/hooks/useAutoSelectFirstEnvironment.esm.js +25 -0
  136. package/dist/hooks/useAutoSelectFirstEnvironment.esm.js.map +1 -0
  137. package/dist/hooks/useComponentAlerts.esm.js +80 -0
  138. package/dist/hooks/useComponentAlerts.esm.js.map +1 -0
  139. package/dist/hooks/useDataPlaneNetPolProvider.esm.js +55 -0
  140. package/dist/hooks/useDataPlaneNetPolProvider.esm.js.map +1 -0
  141. package/dist/hooks/useDebouncedSearch.esm.js +24 -0
  142. package/dist/hooks/useDebouncedSearch.esm.js.map +1 -0
  143. package/dist/hooks/useFilters.esm.js +29 -0
  144. package/dist/hooks/useFilters.esm.js.map +1 -0
  145. package/dist/hooks/useFinOpsReport.esm.js +66 -0
  146. package/dist/hooks/useFinOpsReport.esm.js.map +1 -0
  147. package/dist/hooks/useFinOpsReports.esm.js +70 -0
  148. package/dist/hooks/useFinOpsReports.esm.js.map +1 -0
  149. package/dist/hooks/useGetComponentsByProject.esm.js +57 -0
  150. package/dist/hooks/useGetComponentsByProject.esm.js.map +1 -0
  151. package/dist/hooks/useGetEnvironmentsByNamespace.esm.js +53 -0
  152. package/dist/hooks/useGetEnvironmentsByNamespace.esm.js.map +1 -0
  153. package/dist/hooks/useGetNamespaceAndProjectByEntity.esm.js +40 -0
  154. package/dist/hooks/useGetNamespaceAndProjectByEntity.esm.js.map +1 -0
  155. package/dist/hooks/useMetrics.esm.js +107 -0
  156. package/dist/hooks/useMetrics.esm.js.map +1 -0
  157. package/dist/hooks/useProjectIncidents.esm.js +111 -0
  158. package/dist/hooks/useProjectIncidents.esm.js.map +1 -0
  159. package/dist/hooks/useProjectRuntimeLogs.esm.js +185 -0
  160. package/dist/hooks/useProjectRuntimeLogs.esm.js.map +1 -0
  161. package/dist/hooks/useRCAReportByAlert.esm.js +54 -0
  162. package/dist/hooks/useRCAReportByAlert.esm.js.map +1 -0
  163. package/dist/hooks/useRCAReports.esm.js +75 -0
  164. package/dist/hooks/useRCAReports.esm.js.map +1 -0
  165. package/dist/hooks/useRuntimeLogs.esm.js +147 -0
  166. package/dist/hooks/useRuntimeLogs.esm.js.map +1 -0
  167. package/dist/hooks/useSpanDetails.esm.js +71 -0
  168. package/dist/hooks/useSpanDetails.esm.js.map +1 -0
  169. package/dist/hooks/useTraceSpans.esm.js +80 -0
  170. package/dist/hooks/useTraceSpans.esm.js.map +1 -0
  171. package/dist/hooks/useTraces.esm.js +112 -0
  172. package/dist/hooks/useTraces.esm.js.map +1 -0
  173. package/dist/hooks/useUpdateIncident.esm.js +50 -0
  174. package/dist/hooks/useUpdateIncident.esm.js.map +1 -0
  175. package/dist/hooks/useUrlFilters.esm.js +63 -0
  176. package/dist/hooks/useUrlFilters.esm.js.map +1 -0
  177. package/dist/hooks/useUrlFiltersForAlerts.esm.js +80 -0
  178. package/dist/hooks/useUrlFiltersForAlerts.esm.js.map +1 -0
  179. package/dist/hooks/useUrlFiltersForIncidents.esm.js +87 -0
  180. package/dist/hooks/useUrlFiltersForIncidents.esm.js.map +1 -0
  181. package/dist/hooks/useUrlFiltersForRuntimeLogs.esm.js +135 -0
  182. package/dist/hooks/useUrlFiltersForRuntimeLogs.esm.js.map +1 -0
  183. package/dist/index.d.ts +41 -0
  184. package/dist/index.esm.js +2 -0
  185. package/dist/index.esm.js.map +1 -0
  186. package/dist/plugin.esm.js +107 -0
  187. package/dist/plugin.esm.js.map +1 -0
  188. package/dist/routes.esm.js +8 -0
  189. package/dist/routes.esm.js.map +1 -0
  190. package/dist/types.esm.js +18 -0
  191. package/dist/types.esm.js.map +1 -0
  192. package/dist/utils/applyResourceChange.esm.js +79 -0
  193. package/dist/utils/applyResourceChange.esm.js.map +1 -0
  194. package/dist/utils/urlTimeRange.esm.js +52 -0
  195. package/dist/utils/urlTimeRange.esm.js.map +1 -0
  196. package/package.json +81 -0
package/CHANGELOG.md ADDED
@@ -0,0 +1,5 @@
1
+ # @openchoreo/backstage-plugin-openchoreo-observability
2
+
3
+ ## 1.1.0
4
+
5
+ - Initial public release on GitHub Packages, aligned with the OpenChoreo platform release line (`1.1.0`).
package/README.md ADDED
@@ -0,0 +1,22 @@
1
+ # openchoreo-observability
2
+
3
+ Welcome to the openchoreo-observability plugin!
4
+
5
+ _This plugin was created through the Backstage CLI_
6
+
7
+ ## Features
8
+
9
+ - **Logs**: Component-level and project-level runtime logs with filtering
10
+ - **Metrics**: Resource and HTTP metrics for components
11
+ - **Traces**: Distributed tracing for component requests
12
+ - **Alerts**: Component-level triggered alerts with severity, time range, and environment filters. Alerts can link to the project Incidents tab when incident management is enabled.
13
+ - **Incidents**: Project-level incidents with status, component, and environment filters. Incidents with AI RCA enabled can link to the RCA Reports tab.
14
+ - **RCA Reports**: Root cause analysis reports for incidents
15
+
16
+ ## Getting started
17
+
18
+ Your plugin has been added to the example app in this repository, meaning you'll be able to access it by running `yarn start` in the root directory, and then navigating to [/openchoreo-observability](http://localhost:3000/openchoreo-observability).
19
+
20
+ You can also serve the plugin in isolation by running `yarn start` in the plugin directory.
21
+ This method of serving the plugin provides quicker iteration speed and a faster startup and hot reloads.
22
+ It is only meant for local development, and the setup for it can be found inside the [/dev](./dev) directory.
@@ -0,0 +1,43 @@
1
+ import { createApiRef } from '@backstage/core-plugin-api';
2
+ import { ObserverUrlCache } from './ObserverUrlCache.esm.js';
3
+
4
+ const finopsAgentApiRef = createApiRef({
5
+ id: "plugin.openchoreo-finops-agent.service"
6
+ });
7
+ class FinOpsAgentClient {
8
+ fetchApi;
9
+ urlCache;
10
+ constructor(options) {
11
+ this.fetchApi = options.fetchApi;
12
+ this.urlCache = new ObserverUrlCache(options);
13
+ }
14
+ async updateActionStatuses(reportId, routing, update) {
15
+ const { finopsAgentUrl } = await this.urlCache.resolveUrls(
16
+ routing.namespaceName,
17
+ routing.environmentName
18
+ );
19
+ if (!finopsAgentUrl) {
20
+ throw new Error("FinOps service is not configured");
21
+ }
22
+ const response = await this.fetchApi.fetch(
23
+ `${finopsAgentUrl}/api/v1alpha1/reports/${encodeURIComponent(reportId)}`,
24
+ {
25
+ method: "PUT",
26
+ body: JSON.stringify(update),
27
+ headers: {
28
+ "Content-Type": "application/json",
29
+ "x-openchoreo-direct": "true"
30
+ }
31
+ }
32
+ );
33
+ if (!response.ok) {
34
+ const error = await response.json().catch(() => ({}));
35
+ throw new Error(
36
+ error.detail || `Update report failed: ${response.statusText}`
37
+ );
38
+ }
39
+ }
40
+ }
41
+
42
+ export { FinOpsAgentClient, finopsAgentApiRef };
43
+ //# sourceMappingURL=FinOpsAgentApi.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"FinOpsAgentApi.esm.js","sources":["../../src/api/FinOpsAgentApi.ts"],"sourcesContent":["import {\n createApiRef,\n DiscoveryApi,\n FetchApi,\n} from '@backstage/core-plugin-api';\nimport { ObserverUrlCache } from './ObserverUrlCache';\n\nexport interface FinOpsRoutingContext {\n namespaceName: string;\n environmentName: string;\n}\n\nexport interface FinOpsAgentApi {\n updateActionStatuses(\n reportId: string,\n routing: FinOpsRoutingContext,\n update: { appliedIndices?: number[]; dismissedIndices?: number[] },\n ): Promise<void>;\n}\n\nexport const finopsAgentApiRef = createApiRef<FinOpsAgentApi>({\n id: 'plugin.openchoreo-finops-agent.service',\n});\n\nexport class FinOpsAgentClient implements FinOpsAgentApi {\n private readonly fetchApi: FetchApi;\n private readonly urlCache: ObserverUrlCache;\n\n constructor(options: { discoveryApi: DiscoveryApi; fetchApi: FetchApi }) {\n this.fetchApi = options.fetchApi;\n this.urlCache = new ObserverUrlCache(options);\n }\n\n async updateActionStatuses(\n reportId: string,\n routing: FinOpsRoutingContext,\n update: { appliedIndices?: number[]; dismissedIndices?: number[] },\n ): Promise<void> {\n const { finopsAgentUrl } = await this.urlCache.resolveUrls(\n routing.namespaceName,\n routing.environmentName,\n );\n\n if (!finopsAgentUrl) {\n throw new Error('FinOps service is not configured');\n }\n\n const response = await this.fetchApi.fetch(\n `${finopsAgentUrl}/api/v1alpha1/reports/${encodeURIComponent(reportId)}`,\n {\n method: 'PUT',\n body: JSON.stringify(update),\n headers: {\n 'Content-Type': 'application/json',\n 'x-openchoreo-direct': 'true',\n },\n },\n );\n\n if (!response.ok) {\n const error = await response.json().catch(() => ({}));\n throw new Error(\n error.detail || `Update report failed: ${response.statusText}`,\n );\n }\n }\n}\n"],"names":[],"mappings":";;;AAoBO,MAAM,oBAAoB,YAAA,CAA6B;AAAA,EAC5D,EAAA,EAAI;AACN,CAAC;AAEM,MAAM,iBAAA,CAA4C;AAAA,EACtC,QAAA;AAAA,EACA,QAAA;AAAA,EAEjB,YAAY,OAAA,EAA6D;AACvE,IAAA,IAAA,CAAK,WAAW,OAAA,CAAQ,QAAA;AACxB,IAAA,IAAA,CAAK,QAAA,GAAW,IAAI,gBAAA,CAAiB,OAAO,CAAA;AAAA,EAC9C;AAAA,EAEA,MAAM,oBAAA,CACJ,QAAA,EACA,OAAA,EACA,MAAA,EACe;AACf,IAAA,MAAM,EAAE,cAAA,EAAe,GAAI,MAAM,KAAK,QAAA,CAAS,WAAA;AAAA,MAC7C,OAAA,CAAQ,aAAA;AAAA,MACR,OAAA,CAAQ;AAAA,KACV;AAEA,IAAA,IAAI,CAAC,cAAA,EAAgB;AACnB,MAAA,MAAM,IAAI,MAAM,kCAAkC,CAAA;AAAA,IACpD;AAEA,IAAA,MAAM,QAAA,GAAW,MAAM,IAAA,CAAK,QAAA,CAAS,KAAA;AAAA,MACnC,CAAA,EAAG,cAAc,CAAA,sBAAA,EAAyB,kBAAA,CAAmB,QAAQ,CAAC,CAAA,CAAA;AAAA,MACtE;AAAA,QACE,MAAA,EAAQ,KAAA;AAAA,QACR,IAAA,EAAM,IAAA,CAAK,SAAA,CAAU,MAAM,CAAA;AAAA,QAC3B,OAAA,EAAS;AAAA,UACP,cAAA,EAAgB,kBAAA;AAAA,UAChB,qBAAA,EAAuB;AAAA;AACzB;AACF,KACF;AAEA,IAAA,IAAI,CAAC,SAAS,EAAA,EAAI;AAChB,MAAA,MAAM,KAAA,GAAQ,MAAM,QAAA,CAAS,IAAA,GAAO,KAAA,CAAM,OAAO,EAAC,CAAE,CAAA;AACpD,MAAA,MAAM,IAAI,KAAA;AAAA,QACR,KAAA,CAAM,MAAA,IAAU,CAAA,sBAAA,EAAyB,QAAA,CAAS,UAAU,CAAA;AAAA,OAC9D;AAAA,IACF;AAAA,EACF;AACF;;;;"}
@@ -0,0 +1,568 @@
1
+ import { createApiRef } from '@backstage/core-plugin-api';
2
+ import { ObserverUrlCache } from './ObserverUrlCache.esm.js';
3
+
4
+ const observabilityApiRef = createApiRef({
5
+ id: "plugin.openchoreo-observability.service"
6
+ });
7
+ const DIRECT_HEADER = { "x-openchoreo-direct": "true" };
8
+ class ObservabilityClient {
9
+ fetchApi;
10
+ urlCache;
11
+ constructor(options) {
12
+ this.fetchApi = options.fetchApi;
13
+ this.urlCache = new ObserverUrlCache(options);
14
+ }
15
+ async getMetrics(environmentName, componentName, namespaceName, projectName, options) {
16
+ const { observerUrl } = await this.urlCache.resolveUrls(
17
+ namespaceName,
18
+ environmentName
19
+ );
20
+ const searchScope = {
21
+ namespace: namespaceName,
22
+ project: projectName,
23
+ component: componentName,
24
+ environment: environmentName
25
+ };
26
+ const baseBody = {
27
+ startTime: options?.startTime ?? new Date(Date.now() - 36e5).toISOString(),
28
+ endTime: options?.endTime ?? (/* @__PURE__ */ new Date()).toISOString(),
29
+ searchScope,
30
+ ...options?.step ? { step: options.step } : {}
31
+ };
32
+ const fetchOptions = {
33
+ method: "POST",
34
+ headers: { "Content-Type": "application/json", ...DIRECT_HEADER }
35
+ };
36
+ const metricType = options?.type ?? "resource";
37
+ const response = await this.fetchApi.fetch(
38
+ `${observerUrl}/api/v1/metrics/query`,
39
+ {
40
+ ...fetchOptions,
41
+ body: JSON.stringify({ ...baseBody, metric: metricType })
42
+ }
43
+ );
44
+ if (!response.ok) {
45
+ const error = await this.parseError(response);
46
+ if (error.includes("Observability is not configured for component")) {
47
+ throw new Error("Observability is not enabled for this component");
48
+ }
49
+ throw new Error(
50
+ error || `Failed to fetch metrics: ${response.statusText}`
51
+ );
52
+ }
53
+ const data = await response.json();
54
+ switch (metricType) {
55
+ case "resource":
56
+ return {
57
+ cpuUsage: {
58
+ cpuUsage: data.cpuUsage ?? [],
59
+ cpuRequests: data.cpuRequests ?? [],
60
+ cpuLimits: data.cpuLimits ?? []
61
+ },
62
+ memoryUsage: {
63
+ memoryUsage: data.memoryUsage ?? [],
64
+ memoryRequests: data.memoryRequests ?? [],
65
+ memoryLimits: data.memoryLimits ?? []
66
+ }
67
+ };
68
+ case "http":
69
+ return {
70
+ networkThroughput: {
71
+ requestCount: data.requestCount ?? [],
72
+ successfulRequestCount: data.successfulRequestCount ?? [],
73
+ unsuccessfulRequestCount: data.unsuccessfulRequestCount ?? []
74
+ },
75
+ networkLatency: {
76
+ meanLatency: data.meanLatency ?? [],
77
+ latencyP50: data.latencyP50 ?? [],
78
+ latencyP90: data.latencyP90 ?? [],
79
+ latencyP99: data.latencyP99 ?? []
80
+ }
81
+ };
82
+ default:
83
+ throw new Error(`Unsupported metric type: ${metricType}`);
84
+ }
85
+ }
86
+ async getTraces(namespaceName, projectName, environmentName, componentName, options) {
87
+ const { observerUrl } = await this.urlCache.resolveUrls(
88
+ namespaceName,
89
+ environmentName
90
+ );
91
+ const response = await this.fetchApi.fetch(
92
+ `${observerUrl}/api/v1alpha1/traces/query`,
93
+ {
94
+ method: "POST",
95
+ headers: { "Content-Type": "application/json", ...DIRECT_HEADER },
96
+ body: JSON.stringify({
97
+ startTime: options?.startTime ?? new Date(Date.now() - 36e5).toISOString(),
98
+ endTime: options?.endTime ?? (/* @__PURE__ */ new Date()).toISOString(),
99
+ limit: options?.limit ?? 100,
100
+ sortOrder: options?.sortOrder ?? "desc",
101
+ searchScope: {
102
+ namespace: namespaceName,
103
+ project: projectName,
104
+ ...componentName ? { component: componentName } : {},
105
+ environment: environmentName
106
+ }
107
+ })
108
+ }
109
+ );
110
+ if (!response.ok) {
111
+ const error = await this.parseError(response);
112
+ if (error.includes("Observability is not configured for component")) {
113
+ throw new Error("Observability is not enabled for this component");
114
+ }
115
+ throw new Error(
116
+ error || `Failed to fetch traces: ${response.statusText}`
117
+ );
118
+ }
119
+ const data = await response.json();
120
+ return {
121
+ traces: (data.traces ?? []).map((t) => ({
122
+ traceId: t.traceId ?? "",
123
+ traceName: t.traceName,
124
+ spanCount: t.spanCount ?? 0,
125
+ rootSpanId: t.rootSpanId,
126
+ rootSpanName: t.rootSpanName,
127
+ rootSpanKind: t.rootSpanKind,
128
+ startTime: t.startTime ?? "",
129
+ endTime: t.endTime ?? "",
130
+ durationNs: t.durationNs ?? 0,
131
+ hasErrors: t.hasErrors ?? false
132
+ })),
133
+ total: data.total ?? 0,
134
+ tookMs: data.tookMs ?? 0
135
+ };
136
+ }
137
+ async getTraceSpans(traceId, namespaceName, projectName, environmentName, componentName, options) {
138
+ const { observerUrl } = await this.urlCache.resolveUrls(
139
+ namespaceName,
140
+ environmentName
141
+ );
142
+ const response = await this.fetchApi.fetch(
143
+ `${observerUrl}/api/v1alpha1/traces/${encodeURIComponent(
144
+ traceId
145
+ )}/spans/query`,
146
+ {
147
+ method: "POST",
148
+ headers: { "Content-Type": "application/json", ...DIRECT_HEADER },
149
+ body: JSON.stringify({
150
+ startTime: options?.startTime ?? new Date(Date.now() - 36e5).toISOString(),
151
+ endTime: options?.endTime ?? (/* @__PURE__ */ new Date()).toISOString(),
152
+ limit: 1e3,
153
+ sortOrder: "asc",
154
+ searchScope: {
155
+ namespace: namespaceName,
156
+ project: projectName,
157
+ ...componentName ? { component: componentName } : {},
158
+ environment: environmentName
159
+ }
160
+ })
161
+ }
162
+ );
163
+ if (!response.ok) {
164
+ const error = await this.parseError(response);
165
+ throw new Error(
166
+ error || `Failed to fetch spans for trace ${traceId}: ${response.statusText}`
167
+ );
168
+ }
169
+ const data = await response.json();
170
+ return {
171
+ spans: (data.spans ?? []).map((s) => ({
172
+ spanId: s.spanId ?? "",
173
+ spanName: s.spanName ?? "",
174
+ spanKind: s.spanKind,
175
+ startTime: s.startTime ?? "",
176
+ endTime: s.endTime ?? "",
177
+ durationNs: s.durationNs ?? 0,
178
+ parentSpanId: s.parentSpanId,
179
+ status: s.status
180
+ })),
181
+ total: data.total ?? 0,
182
+ tookMs: data.tookMs ?? 0
183
+ };
184
+ }
185
+ async getSpanDetails(traceId, spanId, namespaceName, environmentName) {
186
+ const { observerUrl } = await this.urlCache.resolveUrls(
187
+ namespaceName,
188
+ environmentName
189
+ );
190
+ const response = await this.fetchApi.fetch(
191
+ `${observerUrl}/api/v1alpha1/traces/${encodeURIComponent(
192
+ traceId
193
+ )}/spans/${encodeURIComponent(spanId)}`,
194
+ {
195
+ headers: { ...DIRECT_HEADER }
196
+ }
197
+ );
198
+ if (!response.ok) {
199
+ const error = await this.parseError(response);
200
+ throw new Error(
201
+ error || `Failed to fetch span details for span ${spanId}: ${response.statusText}`
202
+ );
203
+ }
204
+ const data = await response.json();
205
+ return {
206
+ spanId: data.spanId ?? "",
207
+ spanName: data.spanName ?? "",
208
+ spanKind: data.spanKind,
209
+ startTime: data.startTime ?? "",
210
+ endTime: data.endTime ?? "",
211
+ durationNs: data.durationNs ?? 0,
212
+ parentSpanId: data.parentSpanId,
213
+ attributes: data.attributes,
214
+ resourceAttributes: data.resourceAttributes
215
+ };
216
+ }
217
+ async getRCAReports(namespaceName, projectName, environmentName, options) {
218
+ const { rcaAgentUrl } = await this.urlCache.resolveUrls(
219
+ namespaceName,
220
+ environmentName
221
+ );
222
+ if (!rcaAgentUrl) {
223
+ throw new Error("RCA service is not configured");
224
+ }
225
+ const url = new URL(`${rcaAgentUrl}/api/v1/rca-agent/reports`);
226
+ url.searchParams.set("namespace", namespaceName);
227
+ url.searchParams.set("project", projectName);
228
+ url.searchParams.set("environment", environmentName);
229
+ if (options?.startTime)
230
+ url.searchParams.set("startTime", options.startTime);
231
+ if (options?.endTime) url.searchParams.set("endTime", options.endTime);
232
+ if (options?.status) url.searchParams.set("status", options.status);
233
+ if (options?.limit !== void 0)
234
+ url.searchParams.set("limit", String(options.limit));
235
+ let response;
236
+ try {
237
+ response = await this.fetchApi.fetch(url.toString(), {
238
+ headers: { ...DIRECT_HEADER }
239
+ });
240
+ } catch (err) {
241
+ throw new Error(
242
+ `RCA service is unreachable: ${err instanceof Error ? err.message : err}`
243
+ );
244
+ }
245
+ if (!response.ok) {
246
+ const error = await this.parseError(response);
247
+ if (error.includes("RCA service is not configured")) {
248
+ throw new Error("RCA service is not configured");
249
+ }
250
+ if (error.includes("Observability is not configured for component")) {
251
+ throw new Error("Observability is not enabled for this component");
252
+ }
253
+ throw new Error(
254
+ error || `Failed to fetch RCA reports: ${response.statusText}`
255
+ );
256
+ }
257
+ const data = await response.json();
258
+ return {
259
+ reports: data.reports || [],
260
+ totalCount: data.totalCount
261
+ };
262
+ }
263
+ async getRCAReport(reportId, environmentName, namespaceName) {
264
+ const { rcaAgentUrl } = await this.urlCache.resolveUrls(
265
+ namespaceName,
266
+ environmentName
267
+ );
268
+ if (!rcaAgentUrl) {
269
+ throw new Error("RCA service is not configured");
270
+ }
271
+ const url = new URL(
272
+ `${rcaAgentUrl}/api/v1/rca-agent/reports/${encodeURIComponent(reportId)}`
273
+ );
274
+ let response;
275
+ try {
276
+ response = await this.fetchApi.fetch(url.toString(), {
277
+ headers: { ...DIRECT_HEADER }
278
+ });
279
+ } catch (err) {
280
+ throw new Error(
281
+ `RCA service is unreachable: ${err instanceof Error ? err.message : err}`
282
+ );
283
+ }
284
+ if (!response.ok) {
285
+ const error = await this.parseError(response);
286
+ if (error.includes("RCA service is not configured")) {
287
+ throw new Error("RCA service is not configured");
288
+ }
289
+ if (error.includes("RCA report not found")) {
290
+ throw new Error("RCA report not found");
291
+ }
292
+ throw new Error(
293
+ error || `Failed to fetch RCA report: ${response.statusText}`
294
+ );
295
+ }
296
+ const data = await response.json();
297
+ return data;
298
+ }
299
+ async getIncidents(namespaceName, projectName, environmentName, componentName, options) {
300
+ const { observerUrl } = await this.urlCache.resolveUrls(
301
+ namespaceName,
302
+ environmentName
303
+ );
304
+ const response = await this.fetchApi.fetch(
305
+ `${observerUrl}/api/v1alpha1/incidents/query`,
306
+ {
307
+ method: "POST",
308
+ headers: { "Content-Type": "application/json", ...DIRECT_HEADER },
309
+ body: JSON.stringify({
310
+ startTime: options?.startTime ?? new Date(Date.now() - 36e5).toISOString(),
311
+ endTime: options?.endTime ?? (/* @__PURE__ */ new Date()).toISOString(),
312
+ limit: options?.limit ?? 100,
313
+ sortOrder: options?.sortOrder ?? "desc",
314
+ searchScope: {
315
+ namespace: namespaceName,
316
+ project: projectName,
317
+ ...componentName ? { component: componentName } : {},
318
+ environment: environmentName
319
+ }
320
+ })
321
+ }
322
+ );
323
+ if (!response.ok) {
324
+ const error = await this.parseError(response);
325
+ if (error.includes("Observability is not configured for component")) {
326
+ throw new Error("Observability is not enabled for this component");
327
+ }
328
+ throw new Error(
329
+ error || `Failed to fetch incidents: ${response.statusText}`
330
+ );
331
+ }
332
+ const data = await response.json();
333
+ const validStatuses = ["active", "acknowledged", "resolved"];
334
+ return {
335
+ incidents: (data.incidents ?? []).filter((i) => validStatuses.includes(i.status)).map(
336
+ (i) => ({
337
+ incidentId: i.incidentId ?? "",
338
+ alertId: i.alertId ?? "",
339
+ status: i.status,
340
+ description: i.description,
341
+ notes: i.notes,
342
+ timestamp: i.timestamp,
343
+ triggeredAt: i.triggeredAt,
344
+ acknowledgedAt: i.acknowledgedAt,
345
+ resolvedAt: i.resolvedAt,
346
+ incidentTriggerAiRca: i.incidentTriggerAiRca ?? false,
347
+ incidentTriggerAiCostAnalysis: i.incidentTriggerAiCostAnalysis ?? false,
348
+ projectName: i.labels?.projectName,
349
+ componentName: i.labels?.componentName,
350
+ environmentName: i.labels?.environmentName,
351
+ namespaceName: i.labels?.namespaceName
352
+ })
353
+ ),
354
+ total: data.total ?? 0
355
+ };
356
+ }
357
+ async getAlerts(namespaceName, projectName, environmentName, componentName, options) {
358
+ const { observerUrl } = await this.urlCache.resolveUrls(
359
+ namespaceName,
360
+ environmentName
361
+ );
362
+ const response = await this.fetchApi.fetch(
363
+ `${observerUrl}/api/v1alpha1/alerts/query`,
364
+ {
365
+ method: "POST",
366
+ headers: { "Content-Type": "application/json", ...DIRECT_HEADER },
367
+ body: JSON.stringify({
368
+ startTime: options?.startTime ?? new Date(Date.now() - 36e5).toISOString(),
369
+ endTime: options?.endTime ?? (/* @__PURE__ */ new Date()).toISOString(),
370
+ limit: options?.limit ?? 100,
371
+ sortOrder: options?.sortOrder ?? "desc",
372
+ searchScope: {
373
+ namespace: namespaceName,
374
+ project: projectName,
375
+ component: componentName,
376
+ environment: environmentName
377
+ }
378
+ })
379
+ }
380
+ );
381
+ if (!response.ok) {
382
+ const error = await this.parseError(response);
383
+ if (error.includes("Observability is not configured for component")) {
384
+ throw new Error("Observability is not enabled for this component");
385
+ }
386
+ throw new Error(
387
+ error || `Failed to fetch alerts: ${response.statusText}`
388
+ );
389
+ }
390
+ const data = await response.json();
391
+ return {
392
+ alerts: (data.alerts ?? []).map(
393
+ (a) => ({
394
+ timestamp: a.timestamp,
395
+ alertId: a.alertId ?? "",
396
+ alertValue: a.alertValue,
397
+ ruleName: a.metadata?.alertRule?.name,
398
+ ruleDescription: a.metadata?.alertRule?.description,
399
+ severity: a.metadata?.alertRule?.severity,
400
+ sourceType: a.metadata?.alertRule?.source?.type,
401
+ sourceQuery: a.metadata?.alertRule?.source?.query,
402
+ sourceMetric: a.metadata?.alertRule?.source?.metric,
403
+ projectName: a.metadata?.labels?.projectName,
404
+ componentName: a.metadata?.labels?.componentName,
405
+ environmentName: a.metadata?.labels?.environmentName,
406
+ namespaceName: a.metadata?.labels?.namespaceName,
407
+ notificationChannels: a.notificationChannels ?? [],
408
+ incidentEnabled: a.incidentEnabled ?? false
409
+ })
410
+ ),
411
+ total: data.total ?? 0
412
+ };
413
+ }
414
+ async getRuntimeLogs(namespaceName, projectName, environmentName, componentName, options) {
415
+ const { observerUrl } = await this.urlCache.resolveUrls(
416
+ namespaceName,
417
+ environmentName
418
+ );
419
+ const response = await this.fetchApi.fetch(
420
+ `${observerUrl}/api/v1/logs/query`,
421
+ {
422
+ method: "POST",
423
+ headers: { "Content-Type": "application/json", ...DIRECT_HEADER },
424
+ body: JSON.stringify({
425
+ startTime: options?.startTime || new Date(Date.now() - 60 * 60 * 1e3).toISOString(),
426
+ endTime: options?.endTime || (/* @__PURE__ */ new Date()).toISOString(),
427
+ limit: options?.limit || 100,
428
+ sortOrder: options?.sortOrder || "desc",
429
+ ...options?.logLevels && options.logLevels.length > 0 && { logLevels: options.logLevels },
430
+ ...options?.searchQuery && {
431
+ searchPhrase: options.searchQuery
432
+ },
433
+ searchScope: {
434
+ namespace: namespaceName,
435
+ project: projectName,
436
+ ...componentName ? { component: componentName } : {},
437
+ environment: environmentName
438
+ }
439
+ })
440
+ }
441
+ );
442
+ if (!response.ok) {
443
+ const error = await this.parseError(response);
444
+ if (error.includes("Observability is not configured for component")) {
445
+ throw new Error("Observability is not enabled for this component");
446
+ }
447
+ throw new Error(
448
+ error || `Failed to fetch runtime logs: ${response.status} ${response.statusText}`
449
+ );
450
+ }
451
+ const data = await response.json();
452
+ return data;
453
+ }
454
+ async updateIncidentStatus(incidentId, status, namespaceName, environmentName) {
455
+ const { observerUrl } = await this.urlCache.resolveUrls(
456
+ namespaceName,
457
+ environmentName
458
+ );
459
+ const response = await this.fetchApi.fetch(
460
+ `${observerUrl}/api/v1alpha1/incidents/${encodeURIComponent(incidentId)}`,
461
+ {
462
+ method: "PUT",
463
+ headers: { "Content-Type": "application/json", ...DIRECT_HEADER },
464
+ body: JSON.stringify({ status })
465
+ }
466
+ );
467
+ if (!response.ok) {
468
+ const error = await this.parseError(response);
469
+ throw new Error(
470
+ error || `Failed to update incident: ${response.statusText}`
471
+ );
472
+ }
473
+ }
474
+ async getFinOpsReports(namespaceName, projectName, environmentName, options) {
475
+ const { finopsAgentUrl } = await this.urlCache.resolveUrls(
476
+ namespaceName,
477
+ environmentName
478
+ );
479
+ if (!finopsAgentUrl) {
480
+ throw new Error("FinOps service is not configured");
481
+ }
482
+ const url = new URL(`${finopsAgentUrl}/api/v1alpha1/reports`);
483
+ url.searchParams.set("namespace", namespaceName);
484
+ url.searchParams.set("project", projectName);
485
+ url.searchParams.set("environment", environmentName);
486
+ if (options?.startTime)
487
+ url.searchParams.set("startTime", options.startTime);
488
+ if (options?.endTime) url.searchParams.set("endTime", options.endTime);
489
+ if (options?.status) url.searchParams.set("status", options.status);
490
+ if (options?.limit !== void 0)
491
+ url.searchParams.set("limit", String(options.limit));
492
+ if (options?.sort) url.searchParams.set("sort", options.sort);
493
+ let response;
494
+ try {
495
+ response = await this.fetchApi.fetch(url.toString(), {
496
+ headers: { ...DIRECT_HEADER }
497
+ });
498
+ } catch (err) {
499
+ throw new Error(
500
+ `FinOps service is unreachable: ${err instanceof Error ? err.message : err}`
501
+ );
502
+ }
503
+ if (!response.ok) {
504
+ const error = await this.parseError(response);
505
+ if (error.includes("FinOps service is not configured")) {
506
+ throw new Error("FinOps service is not configured");
507
+ }
508
+ if (error.includes("Observability is not configured for component")) {
509
+ throw new Error("Observability is not enabled for this component");
510
+ }
511
+ throw new Error(
512
+ error || `Failed to fetch FinOps reports: ${response.statusText}`
513
+ );
514
+ }
515
+ const data = await response.json();
516
+ return {
517
+ reports: data.reports || [],
518
+ totalCount: data.totalCount
519
+ };
520
+ }
521
+ async getFinOpsReport(reportId, environmentName, namespaceName) {
522
+ const { finopsAgentUrl } = await this.urlCache.resolveUrls(
523
+ namespaceName,
524
+ environmentName
525
+ );
526
+ if (!finopsAgentUrl) {
527
+ throw new Error("FinOps service is not configured");
528
+ }
529
+ const url = new URL(
530
+ `${finopsAgentUrl}/api/v1alpha1/reports/${encodeURIComponent(reportId)}`
531
+ );
532
+ let response;
533
+ try {
534
+ response = await this.fetchApi.fetch(url.toString(), {
535
+ headers: { ...DIRECT_HEADER }
536
+ });
537
+ } catch (err) {
538
+ throw new Error(
539
+ `FinOps service is unreachable: ${err instanceof Error ? err.message : err}`
540
+ );
541
+ }
542
+ if (!response.ok) {
543
+ const error = await this.parseError(response);
544
+ if (error.includes("FinOps service is not configured")) {
545
+ throw new Error("FinOps service is not configured");
546
+ }
547
+ if (error.includes("FinOps report not found")) {
548
+ throw new Error("FinOps report not found");
549
+ }
550
+ throw new Error(
551
+ error || `Failed to fetch FinOps report: ${response.statusText}`
552
+ );
553
+ }
554
+ const data = await response.json();
555
+ return data;
556
+ }
557
+ async parseError(response) {
558
+ try {
559
+ const error = await response.json();
560
+ return error.error || error.message || `${response.status} ${response.statusText}`;
561
+ } catch {
562
+ return `${response.status} ${response.statusText}`;
563
+ }
564
+ }
565
+ }
566
+
567
+ export { ObservabilityClient, observabilityApiRef };
568
+ //# sourceMappingURL=ObservabilityApi.esm.js.map