@oneuptime/common 12.0.5 → 12.0.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/Models/DatabaseModels/AIRun.ts +33 -0
- package/Models/DatabaseModels/DataSource.ts +744 -0
- package/Models/DatabaseModels/Index.ts +3 -0
- package/Models/DatabaseModels/ProjectCallSMSConfig.ts +10 -2
- package/Models/DatabaseModels/User.ts +2 -0
- package/Models/DatabaseModels/UserOnCallLog.ts +2 -0
- package/Models/DatabaseModels/UserOnCallLogTimeline.ts +2 -0
- package/Models/DatabaseModels/UserSession.ts +2 -0
- package/Models/DatabaseModels/UserTotpAuth.ts +6 -4
- package/Models/DatabaseModels/UserWebAuthn.ts +5 -3
- package/Server/API/AIInsightAPI.ts +47 -4
- package/Server/API/AIInvestigationAPI.ts +25 -0
- package/Server/API/DashboardAPI.ts +176 -492
- package/Server/API/DataSourceAPI.ts +268 -0
- package/Server/API/StatusPageAPI.ts +11 -1
- package/Server/API/UserAPI.ts +119 -0
- package/Server/Infrastructure/ClickhouseConfig.ts +59 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1786303472848-AddDataSourceTable.ts +39 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1786600000000-AddInvestigationAnalysisTldr.ts +24 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1786700000000-DropProjectCallSMSConfigCredentialUniques.ts +76 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +6 -0
- package/Server/Infrastructure/Queue.ts +26 -0
- package/Server/Infrastructure/QueueWorker.ts +17 -0
- package/Server/Middleware/TelemetryIngest.ts +8 -3
- package/Server/Services/AIInsightService.ts +132 -12
- package/Server/Services/AIRunService.ts +34 -0
- package/Server/Services/AIService.ts +17 -2
- package/Server/Services/AlertService.ts +38 -32
- package/Server/Services/AnalyticsDatabaseService.ts +8 -4
- package/Server/Services/DataSourceService.ts +200 -0
- package/Server/Services/HostService.ts +92 -0
- package/Server/Services/IncidentService.ts +45 -0
- package/Server/Services/Index.ts +2 -0
- package/Server/Services/MonitorService.ts +49 -0
- package/Server/Services/MonitorStatusService.ts +166 -0
- package/Server/Services/OpenTelemetryIngestService.ts +255 -184
- package/Server/Services/RumSessionPinService.ts +7 -21
- package/Server/Services/StatusPageSubscriberService.ts +13 -0
- package/Server/Services/UserService.ts +280 -9
- package/Server/Static/Vendor/README.md +62 -0
- package/Server/Static/Vendor/fonts/InterVariable.woff2 +0 -0
- package/Server/Static/Vendor/highlight/highlight.min.js +1244 -0
- package/Server/Static/Vendor/highlight/languages/apache.min.js +15 -0
- package/Server/Static/Vendor/highlight/languages/bash.min.js +21 -0
- package/Server/Static/Vendor/highlight/languages/c.min.js +41 -0
- package/Server/Static/Vendor/highlight/languages/cpp.min.js +47 -0
- package/Server/Static/Vendor/highlight/languages/csharp.min.js +49 -0
- package/Server/Static/Vendor/highlight/languages/css.min.js +31 -0
- package/Server/Static/Vendor/highlight/languages/diff.min.js +9 -0
- package/Server/Static/Vendor/highlight/languages/dns.min.js +11 -0
- package/Server/Static/Vendor/highlight/languages/dockerfile.min.js +8 -0
- package/Server/Static/Vendor/highlight/languages/go.min.js +20 -0
- package/Server/Static/Vendor/highlight/languages/graphql.min.js +12 -0
- package/Server/Static/Vendor/highlight/languages/http.min.js +14 -0
- package/Server/Static/Vendor/highlight/languages/ini.min.js +15 -0
- package/Server/Static/Vendor/highlight/languages/java.min.js +38 -0
- package/Server/Static/Vendor/highlight/languages/javascript.min.js +81 -0
- package/Server/Static/Vendor/highlight/languages/json.min.js +8 -0
- package/Server/Static/Vendor/highlight/languages/kotlin.min.js +46 -0
- package/Server/Static/Vendor/highlight/languages/lua.min.js +15 -0
- package/Server/Static/Vendor/highlight/languages/makefile.min.js +14 -0
- package/Server/Static/Vendor/highlight/languages/nginx.min.js +21 -0
- package/Server/Static/Vendor/highlight/languages/perl.min.js +41 -0
- package/Server/Static/Vendor/highlight/languages/php.min.js +59 -0
- package/Server/Static/Vendor/highlight/languages/powershell.min.js +39 -0
- package/Server/Static/Vendor/highlight/languages/python.min.js +42 -0
- package/Server/Static/Vendor/highlight/languages/r.min.js +26 -0
- package/Server/Static/Vendor/highlight/languages/ruby.min.js +54 -0
- package/Server/Static/Vendor/highlight/languages/rust.min.js +27 -0
- package/Server/Static/Vendor/highlight/languages/scala.min.js +28 -0
- package/Server/Static/Vendor/highlight/languages/sql.min.js +21 -0
- package/Server/Static/Vendor/highlight/languages/swift.min.js +68 -0
- package/Server/Static/Vendor/highlight/languages/typescript.min.js +99 -0
- package/Server/Static/Vendor/highlight/languages/xml.min.js +29 -0
- package/Server/Static/Vendor/highlight/languages/yaml.min.js +28 -0
- package/Server/Static/Vendor/highlight/styles/github-dark.min.css +10 -0
- package/Server/Static/Vendor/highlight/styles/vs2015.min.css +1 -0
- package/Server/Static/Vendor/tailwind/tailwind-3.4.5.js +21028 -0
- package/Server/Types/Database/Permissions/BasePermission.ts +7 -0
- package/Server/Types/Database/Permissions/DeletePermission.ts +2 -0
- package/Server/Types/Database/Permissions/ReadPermission.ts +3 -0
- package/Server/Types/Database/Permissions/TenantPermission.ts +101 -16
- package/Server/Utils/AI/CodeFix/FixRunBudget.ts +2 -2
- package/Server/Utils/AI/SRE/AIInvestigationEngine.ts +90 -11
- package/Server/Utils/AI/SRE/AlertInvestigationRunner.ts +1 -0
- package/Server/Utils/AI/SRE/IncidentInvestigationRunner.ts +1 -0
- package/Server/Utils/AI/SRE/Insights/Detectors/ExceptionIdentity.ts +125 -0
- package/Server/Utils/AI/SRE/Insights/Detectors/ExceptionSpikeDetector.ts +25 -15
- package/Server/Utils/AI/SRE/Insights/Detectors/NewExceptionDetector.ts +256 -57
- package/Server/Utils/AI/SRE/Insights/InsightStore.ts +76 -18
- package/Server/Utils/AI/SRE/InvestigationTldr.ts +352 -0
- package/Server/Utils/AnalyticsDatabase/InsertDedupContext.ts +7 -2
- package/Server/Utils/Dashboard/PublicDashboardResourceListPolicy.ts +1793 -0
- package/Server/Utils/Dashboard/PublicDashboardViewConfig.ts +65 -0
- package/Server/Utils/DataSource/ConnectorRegistry.ts +53 -0
- package/Server/Utils/DataSource/Connectors/ClickHouseConnector.ts +338 -0
- package/Server/Utils/DataSource/Connectors/ElasticsearchConnector.ts +717 -0
- package/Server/Utils/DataSource/Connectors/LokiConnector.ts +606 -0
- package/Server/Utils/DataSource/Connectors/MySqlConnector.ts +307 -0
- package/Server/Utils/DataSource/Connectors/PostgresConnector.ts +260 -0
- package/Server/Utils/DataSource/Connectors/PrometheusConnector.ts +555 -0
- package/Server/Utils/DataSource/Connectors/RestApiConnector.ts +597 -0
- package/Server/Utils/DataSource/Connectors/SqlServerConnector.ts +318 -0
- package/Server/Utils/DataSource/EgressGuard.ts +446 -0
- package/Server/Utils/DataSource/HttpFetch.ts +221 -0
- package/Server/Utils/DataSource/SqlQueryGuard.ts +383 -0
- package/Server/Utils/DataSource/SqlResultShaper.ts +372 -0
- package/Server/Utils/DataSource/Types.ts +93 -0
- package/Server/Utils/Database/PostgresErrorTranslator.ts +172 -17
- package/Server/Utils/InProcessMemo.ts +141 -0
- package/Server/Utils/InstanceHealth/TelemetryIngestion.ts +628 -0
- package/Server/Utils/Monitor/MonitorMetricUtil.ts +58 -0
- package/Server/Utils/Monitor/MonitorResource.ts +14 -0
- package/Server/Utils/Response.ts +12 -1
- package/Server/Utils/SSRFProtection.ts +237 -0
- package/Server/Utils/StartServer.ts +8 -0
- package/Server/Utils/StatusPageSubscriberWebhook.ts +30 -0
- package/Server/Utils/Telemetry/CaptureSpan.ts +30 -18
- package/Server/Utils/Telemetry/IngestionTimestamp.ts +75 -0
- package/Server/Utils/Telemetry/ResourceHeartbeat.ts +99 -7
- package/Server/Utils/Telemetry/Telemetry.ts +112 -1
- package/Server/Utils/Telemetry.ts +104 -3
- package/Server/Utils/VendorAssets.ts +165 -0
- package/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeams.ts +28 -5
- package/Server/Utils/Workspace/Slack/Slack.ts +5 -0
- package/Server/Views/Partials/Head.ejs +21 -7
- package/Tests/App/AdminDashboard/AdminProjectsIdFilter.test.tsx +207 -0
- package/Tests/App/AdminDashboard/AdminUsersIdFilter.test.tsx +216 -0
- package/Tests/App/Dashboard/AIInsightViewActions.test.tsx +422 -0
- package/Tests/App/Dashboard/AddWidgetModal.test.tsx +10 -3
- package/Tests/App/Dashboard/AlertsSideMenu.test.tsx +387 -0
- package/Tests/App/Dashboard/ChatActivityFeed.test.tsx +199 -0
- package/Tests/App/Dashboard/DataSourceChartSyntheticConfig.test.tsx +736 -0
- package/Tests/App/Dashboard/DataSourceQueryEditor.test.tsx +868 -0
- package/Tests/App/Dashboard/DataSourceWidgetCatalog.test.ts +440 -0
- package/Tests/App/Dashboard/DataSourceWidgetFetching.test.tsx +2109 -0
- package/Tests/App/Dashboard/DataSourceWidgetViews.test.tsx +726 -0
- package/Tests/App/Dashboard/IncidentsSideMenu.test.tsx +447 -0
- package/Tests/App/Dashboard/InvestigationPanel.test.tsx +514 -3
- package/Tests/App/Dashboard/ProductMenuBreadcrumbs.test.tsx +391 -0
- package/Tests/App/Dashboard/ScheduledMaintenanceSideMenu.test.tsx +326 -0
- package/Tests/App/Dashboard/SideMenuHarness.tsx +187 -0
- package/Tests/App/Dashboard/WidgetCatalog.test.ts +6 -1
- package/Tests/App/StatusPage/StatusPageResourceExplorer.test.tsx +1858 -0
- package/Tests/Models/DatabaseModels/DataSourceModelSecrets.test.ts +70 -0
- package/Tests/Server/API/AIInvestigationAPI.test.ts +187 -0
- package/Tests/Server/API/DashboardPublicDataSourceStrip.test.ts +686 -0
- package/Tests/Server/API/DashboardPublicResourceListAPI.test.ts +585 -823
- package/Tests/Server/API/DataSourceAPIRoutes.test.ts +486 -0
- package/Tests/Server/API/StatusPageSubscriberOwnership.test.ts +291 -0
- package/Tests/Server/API/UserAuthenticationAPI.test.ts +641 -0
- package/Tests/Server/Infrastructure/ClickhouseKeepAliveOptions.test.ts +441 -0
- package/Tests/Server/Middleware/TelemetryIngestTokenLog.test.ts +140 -0
- package/Tests/Server/Services/AIInsightService.test.ts +266 -11
- package/Tests/Server/Services/AIRunAnalysisTldrPersistence.test.ts +160 -0
- package/Tests/Server/Services/AIServiceDailyBudget.test.ts +4 -0
- package/Tests/Server/Services/AlertMetricResourceAttributes.test.ts +352 -0
- package/Tests/Server/Services/DataSourceServiceSettings.test.ts +244 -0
- package/Tests/Server/Services/HostServiceFindOrCreateMemo.test.ts +397 -0
- package/Tests/Server/Services/HostServiceUpdateLastSeen.test.ts +41 -2
- package/Tests/Server/Services/IncidentMetricResourceAttributes.test.ts +408 -0
- package/Tests/Server/Services/MonitorStatusServiceDeleteReferenceCleanup.test.ts +351 -0
- package/Tests/Server/Services/MonitorStatusServiceValidation.test.ts +171 -0
- package/Tests/Server/Services/OpenTelemetryResourceRetentionMemo.test.ts +398 -0
- package/Tests/Server/Services/OpenTelemetryServiceResolutionCache.test.ts +19 -0
- package/Tests/Server/Services/ProjectCallSMSConfigCredentialUniqueness.test.ts +305 -0
- package/Tests/Server/Services/ResourceUpdateLastSeenLivenessFallback.test.ts +36 -1
- package/Tests/Server/Services/RumSessionPinUniqueViolationRecovery.test.ts +163 -0
- package/Tests/Server/Services/UserAuthenticationService.test.ts +973 -0
- package/Tests/Server/Types/Database/ObjectIdColumnQuery.test.ts +262 -0
- package/Tests/Server/Types/Database/Permissions/TenantPermission.test.ts +358 -0
- package/Tests/Server/Utils/AI/FixRunBudget.test.ts +2 -2
- package/Tests/Server/Utils/AI/Insights/ExceptionSpikeDetector.test.ts +6 -1
- package/Tests/Server/Utils/AI/Insights/InsightStore.test.ts +121 -4
- package/Tests/Server/Utils/AI/Insights/NewExceptionDetector.test.ts +361 -10
- package/Tests/Server/Utils/AI/InvestigationSettlement.test.ts +292 -0
- package/Tests/Server/Utils/AI/InvestigationTldr.test.ts +623 -0
- package/Tests/Server/Utils/AI/InvestigationTldrWiring.test.ts +98 -0
- package/Tests/Server/Utils/Dashboard/PublicDashboardResourceListPolicy.test.ts +857 -0
- package/Tests/Server/Utils/Dashboard/PublicDashboardViewConfig.test.ts +480 -0
- package/Tests/Server/Utils/DataSource/ClickHouseConnector.test.ts +759 -0
- package/Tests/Server/Utils/DataSource/ConnectorRegistry.test.ts +37 -0
- package/Tests/Server/Utils/DataSource/EgressGuard.test.ts +645 -0
- package/Tests/Server/Utils/DataSource/ElasticsearchConnector.test.ts +1206 -0
- package/Tests/Server/Utils/DataSource/HttpFetch.test.ts +616 -0
- package/Tests/Server/Utils/DataSource/LokiConnector.test.ts +970 -0
- package/Tests/Server/Utils/DataSource/MySqlConnector.test.ts +935 -0
- package/Tests/Server/Utils/DataSource/PostgresConnector.test.ts +854 -0
- package/Tests/Server/Utils/DataSource/PrometheusConnector.test.ts +881 -0
- package/Tests/Server/Utils/DataSource/RestApiConnector.test.ts +1020 -0
- package/Tests/Server/Utils/DataSource/SqlQueryGuard.test.ts +425 -0
- package/Tests/Server/Utils/DataSource/SqlResultShaper.test.ts +555 -0
- package/Tests/Server/Utils/DataSource/SqlServerConnector.test.ts +934 -0
- package/Tests/Server/Utils/Database/PostgresErrorTranslator.test.ts +228 -7
- package/Tests/Server/Utils/InProcessMemo.test.ts +292 -0
- package/Tests/Server/Utils/InstanceHealth/TelemetryIngestion.test.ts +960 -0
- package/Tests/Server/Utils/MicrosoftTeamsWebhookUrlValidation.test.ts +103 -0
- package/Tests/Server/Utils/Monitor/MonitorMetricResourceAttributes.test.ts +336 -0
- package/Tests/Server/Utils/OfflineAssetHygiene.test.ts +521 -0
- package/Tests/Server/Utils/ResponseRenderAnalytics.test.ts +143 -0
- package/Tests/Server/Utils/SSRFProtection.test.ts +193 -0
- package/Tests/Server/Utils/StatusPageSubscriberWebhook.test.ts +101 -0
- package/Tests/Server/Utils/TailwindBuildCopy.test.ts +225 -0
- package/Tests/Server/Utils/Telemetry/ResourceHeartbeatL1Memo.test.ts +355 -0
- package/Tests/Server/Utils/Telemetry/TelemetryFanInWriter.test.ts +128 -0
- package/Tests/Server/Utils/Telemetry/TelemetryUtilAttributeKeys.test.ts +381 -0
- package/Tests/Server/Utils/Telemetry.test.ts +87 -0
- package/Tests/Server/Utils/VendorAssetIntegrity.test.ts +343 -0
- package/Tests/Server/Utils/VendorAssets.test.ts +671 -0
- package/Tests/Server/Views/OfflineRender.test.ts +297 -0
- package/Tests/Types/Dashboard/DataSourceComponentTypes.test.ts +618 -0
- package/Tests/Types/DateClickhouseFormat.test.ts +192 -0
- package/Tests/Types/Password.test.ts +363 -0
- package/Tests/UI/Components/ConfirmModal.test.tsx +7 -0
- package/Tests/UI/Components/ErrorBoundary.test.tsx +53 -0
- package/Tests/UI/Components/Modal.test.tsx +281 -1
- package/Tests/UI/Components/ObjectIdFilterPipeline.test.tsx +396 -0
- package/Tests/UI/Components/StatusPage/ResourceGroupNavigator.test.tsx +1147 -0
- package/Tests/UI/Utils/Breadcrumb/fixtures/RealBreadcrumbTrails.ts +116 -1
- package/Tests/UI/Utils/Breadcrumb/fixtures/RealRoutePatterns.ts +2 -0
- package/Tests/Utils/Analytics.test.ts +23 -0
- package/Tests/Utils/Dashboard/Components/DashboardDataSourceComponents.test.ts +640 -0
- package/Tests/Utils/DataSource/DataSourceQueryText.test.ts +138 -0
- package/Tests/Utils/DataSource/DataSourceValueReducer.test.ts +526 -0
- package/Tests/Utils/Metrics/MetricResourceAttributeUtil.test.ts +691 -0
- package/Tests/Utils/StatusPage/GroupHierarchyView.test.ts +1452 -0
- package/Tests/Utils/StatusPage/ResourceExplorer.test.ts +931 -0
- package/Tests/Utils/Telemetry/CaptureSpanExportGating.test.ts +288 -0
- package/Tests/Utils/Telemetry/IngestionTimestamp.test.ts +170 -0
- package/Types/AI/AIInsightEvidence.ts +6 -0
- package/Types/Analytics/RevenueEvent.ts +31 -0
- package/Types/Dashboard/DashboardComponentType.ts +31 -0
- package/Types/Dashboard/DashboardComponents/DashboardDataSourceChartComponent.ts +27 -0
- package/Types/Dashboard/DashboardComponents/DashboardDataSourceGaugeComponent.ts +32 -0
- package/Types/Dashboard/DashboardComponents/DashboardDataSourceTableComponent.ts +30 -0
- package/Types/Dashboard/DashboardComponents/DashboardDataSourceValueComponent.ts +55 -0
- package/Types/DataSource/DataSourceLimits.ts +62 -0
- package/Types/DataSource/DataSourceQueryConfig.ts +41 -0
- package/Types/DataSource/DataSourceTableResult.ts +38 -0
- package/Types/DataSource/DataSourceType.ts +213 -0
- package/Types/Date.ts +43 -3
- package/Types/Password.ts +64 -0
- package/Types/Permission.ts +46 -0
- package/Types/UserAuthenticationStatus.ts +34 -0
- package/UI/Components/Button/Button.tsx +1 -1
- package/UI/Components/ErrorBoundary.tsx +459 -108
- package/UI/Components/Icon/Icon.tsx +10 -9
- package/UI/Components/Modal/ConfirmModal.tsx +6 -1
- package/UI/Components/Modal/Modal.tsx +267 -35
- package/UI/Components/Modal/ModalFooter.tsx +6 -1
- package/UI/Components/MoreMenu/MoreMenu.tsx +19 -4
- package/UI/Components/MoreMenu/MoreMenuItem.tsx +6 -1
- package/UI/Components/StatusPage/ResourceGrid.tsx +314 -0
- package/UI/Components/StatusPage/ResourceGroupNavigator.tsx +808 -0
- package/UI/Components/StatusPage/ResourceList.tsx +570 -0
- package/UI/Styles/Theme.css +18 -0
- package/UI/Utils/API/RequestOptions.ts +7 -0
- package/UI/Utils/AnalyticsModelAPI/AnalyticsModelAPI.ts +1 -0
- package/UI/Utils/ModelAPI/ModelAPI.ts +1 -0
- package/UI/Utils/TestDataSource.ts +61 -0
- package/UI/esbuild-config.js +45 -0
- package/Utils/Analytics.ts +15 -0
- package/Utils/Dashboard/Components/DashboardDataSourceChartComponent.ts +88 -0
- package/Utils/Dashboard/Components/DashboardDataSourceGaugeComponent.ts +123 -0
- package/Utils/Dashboard/Components/DashboardDataSourceShared.ts +16 -0
- package/Utils/Dashboard/Components/DashboardDataSourceTableComponent.ts +72 -0
- package/Utils/Dashboard/Components/DashboardDataSourceValueComponent.ts +126 -0
- package/Utils/Dashboard/Components/Index.ts +28 -0
- package/Utils/DataSource/DataSourceQueryText.ts +94 -0
- package/Utils/DataSource/DataSourceValueReducer.ts +156 -0
- package/Utils/Metrics/MetricResourceAttributeUtil.ts +380 -0
- package/Utils/NetworkDiscovery/ScanTargetUtil.ts +8 -6
- package/Utils/StatusPage/GroupHierarchyView.ts +931 -0
- package/Utils/StatusPage/ResourceExplorer.ts +853 -0
- package/build/dist/Models/DatabaseModels/AIRun.js +34 -0
- package/build/dist/Models/DatabaseModels/AIRun.js.map +1 -1
- package/build/dist/Models/DatabaseModels/DataSource.js +774 -0
- package/build/dist/Models/DatabaseModels/DataSource.js.map +1 -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/ProjectCallSMSConfig.js +14 -4
- package/build/dist/Models/DatabaseModels/ProjectCallSMSConfig.js.map +1 -1
- package/build/dist/Models/DatabaseModels/User.js +2 -0
- package/build/dist/Models/DatabaseModels/User.js.map +1 -1
- package/build/dist/Models/DatabaseModels/UserOnCallLog.js +2 -0
- package/build/dist/Models/DatabaseModels/UserOnCallLog.js.map +1 -1
- package/build/dist/Models/DatabaseModels/UserOnCallLogTimeline.js +2 -0
- package/build/dist/Models/DatabaseModels/UserOnCallLogTimeline.js.map +1 -1
- package/build/dist/Models/DatabaseModels/UserSession.js +2 -0
- package/build/dist/Models/DatabaseModels/UserSession.js.map +1 -1
- package/build/dist/Models/DatabaseModels/UserTotpAuth.js +6 -4
- package/build/dist/Models/DatabaseModels/UserTotpAuth.js.map +1 -1
- package/build/dist/Models/DatabaseModels/UserWebAuthn.js +5 -3
- package/build/dist/Models/DatabaseModels/UserWebAuthn.js.map +1 -1
- package/build/dist/Server/API/AIInsightAPI.js +34 -4
- package/build/dist/Server/API/AIInsightAPI.js.map +1 -1
- package/build/dist/Server/API/AIInvestigationAPI.js +23 -0
- package/build/dist/Server/API/AIInvestigationAPI.js.map +1 -1
- package/build/dist/Server/API/DashboardAPI.js +119 -433
- package/build/dist/Server/API/DashboardAPI.js.map +1 -1
- package/build/dist/Server/API/DataSourceAPI.js +173 -0
- package/build/dist/Server/API/DataSourceAPI.js.map +1 -0
- package/build/dist/Server/API/StatusPageAPI.js +11 -1
- package/build/dist/Server/API/StatusPageAPI.js.map +1 -1
- package/build/dist/Server/API/UserAPI.js +94 -2
- package/build/dist/Server/API/UserAPI.js.map +1 -1
- package/build/dist/Server/Infrastructure/ClickhouseConfig.js +49 -0
- package/build/dist/Server/Infrastructure/ClickhouseConfig.js.map +1 -1
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786303472848-AddDataSourceTable.js +20 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786303472848-AddDataSourceTable.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786600000000-AddInvestigationAnalysisTldr.js +19 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786600000000-AddInvestigationAnalysisTldr.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786700000000-DropProjectCallSMSConfigCredentialUniques.js +64 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786700000000-DropProjectCallSMSConfigCredentialUniques.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +6 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
- package/build/dist/Server/Infrastructure/Queue.js +27 -0
- package/build/dist/Server/Infrastructure/Queue.js.map +1 -1
- package/build/dist/Server/Infrastructure/QueueWorker.js +13 -0
- package/build/dist/Server/Infrastructure/QueueWorker.js.map +1 -1
- package/build/dist/Server/Middleware/TelemetryIngest.js +8 -3
- package/build/dist/Server/Middleware/TelemetryIngest.js.map +1 -1
- package/build/dist/Server/Services/AIInsightService.js +110 -10
- package/build/dist/Server/Services/AIInsightService.js.map +1 -1
- package/build/dist/Server/Services/AIRunService.js +34 -0
- package/build/dist/Server/Services/AIRunService.js.map +1 -1
- package/build/dist/Server/Services/AIService.js +16 -2
- package/build/dist/Server/Services/AIService.js.map +1 -1
- package/build/dist/Server/Services/AlertService.js +28 -35
- package/build/dist/Server/Services/AlertService.js.map +1 -1
- package/build/dist/Server/Services/AnalyticsDatabaseService.js +8 -4
- package/build/dist/Server/Services/AnalyticsDatabaseService.js.map +1 -1
- package/build/dist/Server/Services/DataSourceService.js +159 -0
- package/build/dist/Server/Services/DataSourceService.js.map +1 -0
- package/build/dist/Server/Services/HostService.js +74 -0
- package/build/dist/Server/Services/HostService.js.map +1 -1
- package/build/dist/Server/Services/IncidentService.js +35 -24
- package/build/dist/Server/Services/IncidentService.js.map +1 -1
- package/build/dist/Server/Services/Index.js +2 -0
- package/build/dist/Server/Services/Index.js.map +1 -1
- package/build/dist/Server/Services/MonitorService.js +45 -0
- package/build/dist/Server/Services/MonitorService.js.map +1 -1
- package/build/dist/Server/Services/MonitorStatusService.js +129 -0
- package/build/dist/Server/Services/MonitorStatusService.js.map +1 -1
- package/build/dist/Server/Services/OpenTelemetryIngestService.js +222 -159
- package/build/dist/Server/Services/OpenTelemetryIngestService.js.map +1 -1
- package/build/dist/Server/Services/RumSessionPinService.js +7 -15
- package/build/dist/Server/Services/RumSessionPinService.js.map +1 -1
- package/build/dist/Server/Services/StatusPageSubscriberService.js +10 -0
- package/build/dist/Server/Services/StatusPageSubscriberService.js.map +1 -1
- package/build/dist/Server/Services/UserService.js +241 -10
- package/build/dist/Server/Services/UserService.js.map +1 -1
- package/build/dist/Server/Types/Database/Permissions/BasePermission.js +6 -0
- package/build/dist/Server/Types/Database/Permissions/BasePermission.js.map +1 -1
- package/build/dist/Server/Types/Database/Permissions/DeletePermission.js +1 -0
- package/build/dist/Server/Types/Database/Permissions/DeletePermission.js.map +1 -1
- package/build/dist/Server/Types/Database/Permissions/ReadPermission.js +2 -0
- package/build/dist/Server/Types/Database/Permissions/ReadPermission.js.map +1 -1
- package/build/dist/Server/Types/Database/Permissions/TenantPermission.js +68 -12
- package/build/dist/Server/Types/Database/Permissions/TenantPermission.js.map +1 -1
- package/build/dist/Server/Utils/AI/CodeFix/FixRunBudget.js +2 -2
- package/build/dist/Server/Utils/AI/CodeFix/FixRunBudget.js.map +1 -1
- package/build/dist/Server/Utils/AI/SRE/AIInvestigationEngine.js +68 -8
- package/build/dist/Server/Utils/AI/SRE/AIInvestigationEngine.js.map +1 -1
- package/build/dist/Server/Utils/AI/SRE/AlertInvestigationRunner.js +1 -0
- package/build/dist/Server/Utils/AI/SRE/AlertInvestigationRunner.js.map +1 -1
- package/build/dist/Server/Utils/AI/SRE/IncidentInvestigationRunner.js +1 -0
- package/build/dist/Server/Utils/AI/SRE/IncidentInvestigationRunner.js.map +1 -1
- package/build/dist/Server/Utils/AI/SRE/Insights/Detectors/ExceptionIdentity.js +97 -0
- package/build/dist/Server/Utils/AI/SRE/Insights/Detectors/ExceptionIdentity.js.map +1 -0
- package/build/dist/Server/Utils/AI/SRE/Insights/Detectors/ExceptionSpikeDetector.js +17 -15
- package/build/dist/Server/Utils/AI/SRE/Insights/Detectors/ExceptionSpikeDetector.js.map +1 -1
- package/build/dist/Server/Utils/AI/SRE/Insights/Detectors/NewExceptionDetector.js +178 -54
- package/build/dist/Server/Utils/AI/SRE/Insights/Detectors/NewExceptionDetector.js.map +1 -1
- package/build/dist/Server/Utils/AI/SRE/Insights/InsightStore.js +65 -16
- package/build/dist/Server/Utils/AI/SRE/Insights/InsightStore.js.map +1 -1
- package/build/dist/Server/Utils/AI/SRE/InvestigationTldr.js +303 -0
- package/build/dist/Server/Utils/AI/SRE/InvestigationTldr.js.map +1 -0
- package/build/dist/Server/Utils/AnalyticsDatabase/InsertDedupContext.js.map +1 -1
- package/build/dist/Server/Utils/Dashboard/PublicDashboardResourceListPolicy.js +1261 -0
- package/build/dist/Server/Utils/Dashboard/PublicDashboardResourceListPolicy.js.map +1 -0
- package/build/dist/Server/Utils/Dashboard/PublicDashboardViewConfig.js +47 -0
- package/build/dist/Server/Utils/Dashboard/PublicDashboardViewConfig.js.map +1 -0
- package/build/dist/Server/Utils/DataSource/ConnectorRegistry.js +42 -0
- package/build/dist/Server/Utils/DataSource/ConnectorRegistry.js.map +1 -0
- package/build/dist/Server/Utils/DataSource/Connectors/ClickHouseConnector.js +187 -0
- package/build/dist/Server/Utils/DataSource/Connectors/ClickHouseConnector.js.map +1 -0
- package/build/dist/Server/Utils/DataSource/Connectors/ElasticsearchConnector.js +493 -0
- package/build/dist/Server/Utils/DataSource/Connectors/ElasticsearchConnector.js.map +1 -0
- package/build/dist/Server/Utils/DataSource/Connectors/LokiConnector.js +399 -0
- package/build/dist/Server/Utils/DataSource/Connectors/LokiConnector.js.map +1 -0
- package/build/dist/Server/Utils/DataSource/Connectors/MySqlConnector.js +195 -0
- package/build/dist/Server/Utils/DataSource/Connectors/MySqlConnector.js.map +1 -0
- package/build/dist/Server/Utils/DataSource/Connectors/PostgresConnector.js +149 -0
- package/build/dist/Server/Utils/DataSource/Connectors/PostgresConnector.js.map +1 -0
- package/build/dist/Server/Utils/DataSource/Connectors/PrometheusConnector.js +362 -0
- package/build/dist/Server/Utils/DataSource/Connectors/PrometheusConnector.js.map +1 -0
- package/build/dist/Server/Utils/DataSource/Connectors/RestApiConnector.js +342 -0
- package/build/dist/Server/Utils/DataSource/Connectors/RestApiConnector.js.map +1 -0
- package/build/dist/Server/Utils/DataSource/Connectors/SqlServerConnector.js +186 -0
- package/build/dist/Server/Utils/DataSource/Connectors/SqlServerConnector.js.map +1 -0
- package/build/dist/Server/Utils/DataSource/EgressGuard.js +305 -0
- package/build/dist/Server/Utils/DataSource/EgressGuard.js.map +1 -0
- package/build/dist/Server/Utils/DataSource/HttpFetch.js +134 -0
- package/build/dist/Server/Utils/DataSource/HttpFetch.js.map +1 -0
- package/build/dist/Server/Utils/DataSource/SqlQueryGuard.js +331 -0
- package/build/dist/Server/Utils/DataSource/SqlQueryGuard.js.map +1 -0
- package/build/dist/Server/Utils/DataSource/SqlResultShaper.js +280 -0
- package/build/dist/Server/Utils/DataSource/SqlResultShaper.js.map +1 -0
- package/build/dist/Server/Utils/DataSource/Types.js +2 -0
- package/build/dist/Server/Utils/DataSource/Types.js.map +1 -0
- package/build/dist/Server/Utils/Database/PostgresErrorTranslator.js +103 -9
- package/build/dist/Server/Utils/Database/PostgresErrorTranslator.js.map +1 -1
- package/build/dist/Server/Utils/InProcessMemo.js +113 -0
- package/build/dist/Server/Utils/InProcessMemo.js.map +1 -0
- package/build/dist/Server/Utils/InstanceHealth/TelemetryIngestion.js +406 -0
- package/build/dist/Server/Utils/InstanceHealth/TelemetryIngestion.js.map +1 -0
- package/build/dist/Server/Utils/Monitor/MonitorMetricUtil.js +34 -0
- package/build/dist/Server/Utils/Monitor/MonitorMetricUtil.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/MonitorResource.js +14 -0
- package/build/dist/Server/Utils/Monitor/MonitorResource.js.map +1 -1
- package/build/dist/Server/Utils/Response.js +9 -1
- package/build/dist/Server/Utils/Response.js.map +1 -1
- package/build/dist/Server/Utils/SSRFProtection.js +192 -0
- package/build/dist/Server/Utils/SSRFProtection.js.map +1 -0
- package/build/dist/Server/Utils/StartServer.js +7 -0
- package/build/dist/Server/Utils/StartServer.js.map +1 -1
- package/build/dist/Server/Utils/StatusPageSubscriberWebhook.js +24 -0
- package/build/dist/Server/Utils/StatusPageSubscriberWebhook.js.map +1 -1
- package/build/dist/Server/Utils/Telemetry/CaptureSpan.js +25 -11
- package/build/dist/Server/Utils/Telemetry/CaptureSpan.js.map +1 -1
- package/build/dist/Server/Utils/Telemetry/IngestionTimestamp.js +32 -0
- package/build/dist/Server/Utils/Telemetry/IngestionTimestamp.js.map +1 -0
- package/build/dist/Server/Utils/Telemetry/ResourceHeartbeat.js +92 -5
- package/build/dist/Server/Utils/Telemetry/ResourceHeartbeat.js.map +1 -1
- package/build/dist/Server/Utils/Telemetry/Telemetry.js +92 -6
- package/build/dist/Server/Utils/Telemetry/Telemetry.js.map +1 -1
- package/build/dist/Server/Utils/Telemetry.js +93 -6
- package/build/dist/Server/Utils/Telemetry.js.map +1 -1
- package/build/dist/Server/Utils/VendorAssets.js +121 -0
- package/build/dist/Server/Utils/VendorAssets.js.map +1 -0
- package/build/dist/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeams.js +25 -4
- package/build/dist/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeams.js.map +1 -1
- package/build/dist/Server/Utils/Workspace/Slack/Slack.js +5 -0
- package/build/dist/Server/Utils/Workspace/Slack/Slack.js.map +1 -1
- package/build/dist/Types/Analytics/RevenueEvent.js +26 -0
- package/build/dist/Types/Analytics/RevenueEvent.js.map +1 -0
- package/build/dist/Types/Dashboard/DashboardComponentType.js +27 -0
- package/build/dist/Types/Dashboard/DashboardComponentType.js.map +1 -1
- package/build/dist/Types/Dashboard/DashboardComponents/DashboardDataSourceChartComponent.js +2 -0
- package/build/dist/Types/Dashboard/DashboardComponents/DashboardDataSourceChartComponent.js.map +1 -0
- package/build/dist/Types/Dashboard/DashboardComponents/DashboardDataSourceGaugeComponent.js +2 -0
- package/build/dist/Types/Dashboard/DashboardComponents/DashboardDataSourceGaugeComponent.js.map +1 -0
- package/build/dist/Types/Dashboard/DashboardComponents/DashboardDataSourceTableComponent.js +2 -0
- package/build/dist/Types/Dashboard/DashboardComponents/DashboardDataSourceTableComponent.js.map +1 -0
- package/build/dist/Types/Dashboard/DashboardComponents/DashboardDataSourceValueComponent.js +16 -0
- package/build/dist/Types/Dashboard/DashboardComponents/DashboardDataSourceValueComponent.js.map +1 -0
- package/build/dist/Types/DataSource/DataSourceLimits.js +47 -0
- package/build/dist/Types/DataSource/DataSourceLimits.js.map +1 -0
- package/build/dist/Types/DataSource/DataSourceQueryConfig.js +10 -0
- package/build/dist/Types/DataSource/DataSourceQueryConfig.js.map +1 -0
- package/build/dist/Types/DataSource/DataSourceTableResult.js +14 -0
- package/build/dist/Types/DataSource/DataSourceTableResult.js.map +1 -0
- package/build/dist/Types/DataSource/DataSourceType.js +183 -0
- package/build/dist/Types/DataSource/DataSourceType.js.map +1 -0
- package/build/dist/Types/Date.js +38 -3
- package/build/dist/Types/Date.js.map +1 -1
- package/build/dist/Types/Password.js +56 -0
- package/build/dist/Types/Password.js.map +1 -0
- package/build/dist/Types/Permission.js +42 -0
- package/build/dist/Types/Permission.js.map +1 -1
- package/build/dist/Types/UserAuthenticationStatus.js +2 -0
- package/build/dist/Types/UserAuthenticationStatus.js.map +1 -0
- package/build/dist/UI/Components/ErrorBoundary.js +388 -72
- package/build/dist/UI/Components/ErrorBoundary.js.map +1 -1
- package/build/dist/UI/Components/Icon/Icon.js +10 -4
- package/build/dist/UI/Components/Icon/Icon.js.map +1 -1
- package/build/dist/UI/Components/Modal/ConfirmModal.js +1 -1
- package/build/dist/UI/Components/Modal/ConfirmModal.js.map +1 -1
- package/build/dist/UI/Components/Modal/Modal.js +178 -19
- package/build/dist/UI/Components/Modal/Modal.js.map +1 -1
- package/build/dist/UI/Components/Modal/ModalFooter.js +3 -1
- package/build/dist/UI/Components/Modal/ModalFooter.js.map +1 -1
- package/build/dist/UI/Components/MoreMenu/MoreMenu.js +9 -6
- package/build/dist/UI/Components/MoreMenu/MoreMenu.js.map +1 -1
- package/build/dist/UI/Components/MoreMenu/MoreMenuItem.js +7 -1
- package/build/dist/UI/Components/MoreMenu/MoreMenuItem.js.map +1 -1
- package/build/dist/UI/Components/StatusPage/ResourceGrid.js +119 -0
- package/build/dist/UI/Components/StatusPage/ResourceGrid.js.map +1 -0
- package/build/dist/UI/Components/StatusPage/ResourceGroupNavigator.js +354 -0
- package/build/dist/UI/Components/StatusPage/ResourceGroupNavigator.js.map +1 -0
- package/build/dist/UI/Components/StatusPage/ResourceList.js +203 -0
- package/build/dist/UI/Components/StatusPage/ResourceList.js.map +1 -0
- package/build/dist/UI/Utils/AnalyticsModelAPI/AnalyticsModelAPI.js +1 -6
- package/build/dist/UI/Utils/AnalyticsModelAPI/AnalyticsModelAPI.js.map +1 -1
- package/build/dist/UI/Utils/ModelAPI/ModelAPI.js +3 -8
- package/build/dist/UI/Utils/ModelAPI/ModelAPI.js.map +1 -1
- package/build/dist/UI/Utils/TestDataSource.js +39 -0
- package/build/dist/UI/Utils/TestDataSource.js.map +1 -0
- package/build/dist/Utils/Analytics.js +4 -0
- package/build/dist/Utils/Analytics.js.map +1 -1
- package/build/dist/Utils/Dashboard/Components/DashboardDataSourceChartComponent.js +79 -0
- package/build/dist/Utils/Dashboard/Components/DashboardDataSourceChartComponent.js.map +1 -0
- package/build/dist/Utils/Dashboard/Components/DashboardDataSourceGaugeComponent.js +111 -0
- package/build/dist/Utils/Dashboard/Components/DashboardDataSourceGaugeComponent.js.map +1 -0
- package/build/dist/Utils/Dashboard/Components/DashboardDataSourceShared.js +15 -0
- package/build/dist/Utils/Dashboard/Components/DashboardDataSourceShared.js.map +1 -0
- package/build/dist/Utils/Dashboard/Components/DashboardDataSourceTableComponent.js +62 -0
- package/build/dist/Utils/Dashboard/Components/DashboardDataSourceTableComponent.js.map +1 -0
- package/build/dist/Utils/Dashboard/Components/DashboardDataSourceValueComponent.js +112 -0
- package/build/dist/Utils/Dashboard/Components/DashboardDataSourceValueComponent.js.map +1 -0
- package/build/dist/Utils/Dashboard/Components/Index.js +16 -0
- package/build/dist/Utils/Dashboard/Components/Index.js.map +1 -1
- package/build/dist/Utils/DataSource/DataSourceQueryText.js +64 -0
- package/build/dist/Utils/DataSource/DataSourceQueryText.js.map +1 -0
- package/build/dist/Utils/DataSource/DataSourceValueReducer.js +124 -0
- package/build/dist/Utils/DataSource/DataSourceValueReducer.js.map +1 -0
- package/build/dist/Utils/Metrics/MetricResourceAttributeUtil.js +281 -0
- package/build/dist/Utils/Metrics/MetricResourceAttributeUtil.js.map +1 -0
- package/build/dist/Utils/NetworkDiscovery/ScanTargetUtil.js +8 -6
- package/build/dist/Utils/NetworkDiscovery/ScanTargetUtil.js.map +1 -1
- package/build/dist/Utils/StatusPage/GroupHierarchyView.js +560 -0
- package/build/dist/Utils/StatusPage/GroupHierarchyView.js.map +1 -0
- package/build/dist/Utils/StatusPage/ResourceExplorer.js +519 -0
- package/build/dist/Utils/StatusPage/ResourceExplorer.js.map +1 -0
- package/jest.config.json +1 -0
- package/package.json +5 -1
- package/tsconfig.json +12 -10
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import logger from "../Logger";
|
|
2
2
|
import CaptureSpan from "../Telemetry/CaptureSpan";
|
|
3
3
|
import TelemetryUtil from "../Telemetry/Telemetry";
|
|
4
|
+
import MetricResourceAttributeUtil from "../../../Utils/Metrics/MetricResourceAttributeUtil";
|
|
4
5
|
import MetricService from "../../Services/MetricService";
|
|
5
6
|
import GlobalConfigService from "../../Services/GlobalConfigService";
|
|
6
7
|
import GlobalConfig from "../../../Models/DatabaseModels/GlobalConfig";
|
|
@@ -8,6 +9,7 @@ import DataToProcess from "./DataToProcess";
|
|
|
8
9
|
import { MetricPointType } from "../../../Models/AnalyticsModels/Metric";
|
|
9
10
|
import ServiceType from "../../../Types/Telemetry/ServiceType";
|
|
10
11
|
import MetricType from "../../../Models/DatabaseModels/MetricType";
|
|
12
|
+
import Label from "../../../Models/DatabaseModels/Label";
|
|
11
13
|
import BasicInfrastructureMetrics, {
|
|
12
14
|
NetworkInterfaceMetrics,
|
|
13
15
|
} from "../../../Types/Infrastructure/BasicMetrics";
|
|
@@ -234,6 +236,47 @@ export default class MonitorMetricUtil {
|
|
|
234
236
|
data.metricNameServiceNameMap[data.metricName] = metricType;
|
|
235
237
|
}
|
|
236
238
|
|
|
239
|
+
/**
|
|
240
|
+
* Stamp every metric row produced by one monitor check with the monitor's
|
|
241
|
+
* label and custom field attributes.
|
|
242
|
+
*
|
|
243
|
+
* Done as a single pass over the finished rows rather than threaded through
|
|
244
|
+
* the ~30 emission sites below: every metric from one check describes the
|
|
245
|
+
* same monitor, so there is nothing per-metric to decide, and one pass is
|
|
246
|
+
* far easier to keep correct than thirty call sites.
|
|
247
|
+
*
|
|
248
|
+
* Resource attributes are merged LAST. Custom code monitors let a user
|
|
249
|
+
* supply their own attribute names, and those must not be able to shadow the
|
|
250
|
+
* oneuptime.* namespace.
|
|
251
|
+
*/
|
|
252
|
+
public static applyResourceAttributesToMetricRows(data: {
|
|
253
|
+
metricRows: Array<JSONObject>;
|
|
254
|
+
labels?: Array<Label> | undefined;
|
|
255
|
+
customFields?: JSONObject | undefined;
|
|
256
|
+
}): void {
|
|
257
|
+
const resourceAttributes: JSONObject =
|
|
258
|
+
MetricResourceAttributeUtil.getResourceAttributes({
|
|
259
|
+
labels: data.labels,
|
|
260
|
+
customFields: data.customFields,
|
|
261
|
+
});
|
|
262
|
+
|
|
263
|
+
if (Object.keys(resourceAttributes).length === 0) {
|
|
264
|
+
// Nothing to stamp; leave the rows (and their attributeKeys) untouched.
|
|
265
|
+
return;
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
for (const metricRow of data.metricRows) {
|
|
269
|
+
const attributes: JSONObject =
|
|
270
|
+
MetricResourceAttributeUtil.mergeResourceAttributes(
|
|
271
|
+
(metricRow["attributes"] as JSONObject) || {},
|
|
272
|
+
resourceAttributes,
|
|
273
|
+
);
|
|
274
|
+
|
|
275
|
+
metricRow["attributes"] = attributes;
|
|
276
|
+
metricRow["attributeKeys"] = TelemetryUtil.getAttributeKeys(attributes);
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
|
|
237
280
|
@CaptureSpan()
|
|
238
281
|
public static async saveMonitorMetrics(data: {
|
|
239
282
|
monitorId: ObjectID;
|
|
@@ -241,6 +284,15 @@ export default class MonitorMetricUtil {
|
|
|
241
284
|
dataToProcess: DataToProcess;
|
|
242
285
|
probeName: string | undefined;
|
|
243
286
|
monitorName: string | undefined;
|
|
287
|
+
/*
|
|
288
|
+
* The monitor's own taxonomy, passed in by the caller which has already
|
|
289
|
+
* loaded the monitor — this is the hottest Postgres path in the product,
|
|
290
|
+
* so nothing here re-reads it. Both are optional: callers that do not
|
|
291
|
+
* select them simply record no oneuptime.label.* / oneuptime.customField.*
|
|
292
|
+
* attributes.
|
|
293
|
+
*/
|
|
294
|
+
monitorLabels?: Array<Label> | undefined;
|
|
295
|
+
monitorCustomFields?: JSONObject | undefined;
|
|
244
296
|
}): Promise<void> {
|
|
245
297
|
if (!data.monitorId) {
|
|
246
298
|
return;
|
|
@@ -1340,6 +1392,12 @@ export default class MonitorMetricUtil {
|
|
|
1340
1392
|
metricNameServiceNameMap[prefixedName] = metricType;
|
|
1341
1393
|
}
|
|
1342
1394
|
|
|
1395
|
+
this.applyResourceAttributesToMetricRows({
|
|
1396
|
+
metricRows: metricRows,
|
|
1397
|
+
labels: data.monitorLabels,
|
|
1398
|
+
customFields: data.monitorCustomFields,
|
|
1399
|
+
});
|
|
1400
|
+
|
|
1343
1401
|
if (metricRows.length > 0) {
|
|
1344
1402
|
await MetricService.insertJsonRows(metricRows);
|
|
1345
1403
|
}
|
|
@@ -138,6 +138,18 @@ export default class MonitorResourceUtil {
|
|
|
138
138
|
_id: true,
|
|
139
139
|
name: true,
|
|
140
140
|
minimumProbeAgreement: true,
|
|
141
|
+
/*
|
|
142
|
+
* Recorded as oneuptime.label.* / oneuptime.customField.* attributes on
|
|
143
|
+
* every monitor metric this result produces, so response time and
|
|
144
|
+
* uptime are groupable by a project's own taxonomy. Selected here
|
|
145
|
+
* rather than re-read inside MonitorMetricUtil: this is the hottest
|
|
146
|
+
* Postgres path in the product and it already loads the monitor.
|
|
147
|
+
*/
|
|
148
|
+
labels: {
|
|
149
|
+
_id: true,
|
|
150
|
+
name: true,
|
|
151
|
+
},
|
|
152
|
+
customFields: true,
|
|
141
153
|
},
|
|
142
154
|
props: {
|
|
143
155
|
isRoot: true,
|
|
@@ -480,6 +492,8 @@ export default class MonitorResourceUtil {
|
|
|
480
492
|
dataToProcess: dataToProcess,
|
|
481
493
|
probeName: probeName || undefined,
|
|
482
494
|
monitorName: monitorName || undefined,
|
|
495
|
+
monitorLabels: monitor.labels || undefined,
|
|
496
|
+
monitorCustomFields: monitor.customFields || undefined,
|
|
483
497
|
});
|
|
484
498
|
} catch (err) {
|
|
485
499
|
logger.error("Unable to save metrics");
|
package/Server/Utils/Response.ts
CHANGED
|
@@ -24,6 +24,7 @@ import ListData from "../../Types/ListData";
|
|
|
24
24
|
import PositiveNumber from "../../Types/PositiveNumber";
|
|
25
25
|
import Route from "../../Types/API/Route";
|
|
26
26
|
import CaptureSpan from "./Telemetry/CaptureSpan";
|
|
27
|
+
import { IsBillingEnabled } from "../EnvironmentConfig";
|
|
27
28
|
|
|
28
29
|
export default class Response {
|
|
29
30
|
@CaptureSpan()
|
|
@@ -94,7 +95,17 @@ export default class Response {
|
|
|
94
95
|
): void {
|
|
95
96
|
const oneUptimeResponse: OneUptimeResponse = res as OneUptimeResponse;
|
|
96
97
|
|
|
97
|
-
|
|
98
|
+
/*
|
|
99
|
+
* Analytics is opt-in per render, and off unless this is the hosted
|
|
100
|
+
* product. A self-hosted install has no reason to load Google Tag Manager
|
|
101
|
+
* from googletagmanager.com, and an air-gapped one cannot - it would just
|
|
102
|
+
* be another request left hanging. Same default the frontend index pages
|
|
103
|
+
* already use; passing the flag explicitly still wins.
|
|
104
|
+
*/
|
|
105
|
+
oneUptimeResponse.render(path, {
|
|
106
|
+
enableGoogleTagManager: IsBillingEnabled,
|
|
107
|
+
...vars,
|
|
108
|
+
});
|
|
98
109
|
}
|
|
99
110
|
|
|
100
111
|
@CaptureSpan()
|
|
@@ -0,0 +1,237 @@
|
|
|
1
|
+
import URL from "../../Types/API/URL";
|
|
2
|
+
import BadDataException from "../../Types/Exception/BadDataException";
|
|
3
|
+
import dns from "dns";
|
|
4
|
+
|
|
5
|
+
const IPV4_LITERAL_REGEX: RegExp = /^(\d{1,3}\.){3}\d{1,3}$/;
|
|
6
|
+
const IPV6_UNIQUE_LOCAL_REGEX: RegExp = /^f[cd][0-9a-f]{2}:/;
|
|
7
|
+
|
|
8
|
+
/*
|
|
9
|
+
* Guards outbound HTTP(S) requests whose target is (fully or partly)
|
|
10
|
+
* attacker-controlled — status page subscriber webhooks, project webhook
|
|
11
|
+
* notifications, etc. — against Server-Side Request Forgery. It rejects URLs
|
|
12
|
+
* that point at loopback, RFC-1918 private ranges, link-local (including the
|
|
13
|
+
* 169.254.169.254 cloud metadata endpoint), CGNAT, and IPv6 loopback /
|
|
14
|
+
* link-local / unique-local addresses, resolving DNS hostnames first so a
|
|
15
|
+
* public-looking name that maps to an internal address is still blocked.
|
|
16
|
+
*
|
|
17
|
+
* This is a best-effort, TOCTOU-susceptible check: a hostname can resolve to a
|
|
18
|
+
* different address between validation and the actual request (DNS rebinding).
|
|
19
|
+
* Callers should therefore ALSO disable redirect-following on the request so a
|
|
20
|
+
* validated public host cannot 3xx-redirect the server to an internal target.
|
|
21
|
+
*/
|
|
22
|
+
export default class SSRFProtection {
|
|
23
|
+
/*
|
|
24
|
+
* Returns the bare, lowercased host of a URL — no port, no brackets — or an
|
|
25
|
+
* empty string if it cannot be parsed. Host-pinning allowlists (Slack, Teams)
|
|
26
|
+
* must compare against THIS, never against the whole URL string: a substring
|
|
27
|
+
* check on the full URL is satisfied by an attacker-controlled path or query
|
|
28
|
+
* (`http://169.254.169.254/?x=office.com`) and pins nothing.
|
|
29
|
+
*/
|
|
30
|
+
public static getBareHostname(rawUrl: string | URL): string {
|
|
31
|
+
let parsed: URL;
|
|
32
|
+
try {
|
|
33
|
+
parsed = URL.fromString(rawUrl.toString());
|
|
34
|
+
} catch {
|
|
35
|
+
return "";
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
return SSRFProtection.extractHost(parsed.hostname.hostname.toLowerCase());
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/*
|
|
42
|
+
* True when the URL's host is exactly one of `allowedDomains` or a subdomain
|
|
43
|
+
* of one, and the scheme is https. Suffix matching is anchored on a leading
|
|
44
|
+
* dot so `office.com.attacker.tld` and `evil-office.com` are both rejected.
|
|
45
|
+
*/
|
|
46
|
+
public static isUrlOnAllowedDomain(
|
|
47
|
+
rawUrl: string | URL,
|
|
48
|
+
allowedDomains: Array<string>,
|
|
49
|
+
): boolean {
|
|
50
|
+
let parsed: URL;
|
|
51
|
+
try {
|
|
52
|
+
parsed = URL.fromString(rawUrl.toString());
|
|
53
|
+
} catch {
|
|
54
|
+
return false;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
if (parsed.protocol.toString().toLowerCase() !== "https://") {
|
|
58
|
+
return false;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
const hostname: string = SSRFProtection.getBareHostname(rawUrl);
|
|
62
|
+
|
|
63
|
+
if (!hostname) {
|
|
64
|
+
return false;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
return allowedDomains.some((domain: string) => {
|
|
68
|
+
const allowed: string = domain.toLowerCase();
|
|
69
|
+
return hostname === allowed || hostname.endsWith(`.${allowed}`);
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
public static async validateWebhookTargetIsSafe(
|
|
74
|
+
rawUrl: string | URL,
|
|
75
|
+
): Promise<void> {
|
|
76
|
+
let parsed: URL;
|
|
77
|
+
try {
|
|
78
|
+
parsed = URL.fromString(rawUrl.toString());
|
|
79
|
+
} catch {
|
|
80
|
+
throw new BadDataException("Webhook URL is not a valid URL");
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
const protocolValue: string = parsed.protocol.toString().toLowerCase();
|
|
84
|
+
if (protocolValue !== "http://" && protocolValue !== "https://") {
|
|
85
|
+
throw new BadDataException(
|
|
86
|
+
"Webhook URL must use http or https protocol.",
|
|
87
|
+
);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
const rawHost: string = parsed.hostname.hostname.toLowerCase();
|
|
91
|
+
|
|
92
|
+
if (!rawHost) {
|
|
93
|
+
throw new BadDataException("Webhook URL must include a host.");
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/*
|
|
97
|
+
* OneUptime's URL parser keeps the port glued to the host (e.g.
|
|
98
|
+
* "169.254.169.254:80"). Strip it before the checks below, otherwise a
|
|
99
|
+
* literal-with-port slips past the IPv4 blocklist and, because it contains
|
|
100
|
+
* a ":", is mistaken for an IP literal and skips DNS resolution entirely.
|
|
101
|
+
*/
|
|
102
|
+
const hostname: string = SSRFProtection.extractHost(rawHost);
|
|
103
|
+
|
|
104
|
+
if (!hostname) {
|
|
105
|
+
throw new BadDataException("Webhook URL must include a host.");
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
if (SSRFProtection.isBlockedHostnameLiteral(hostname)) {
|
|
109
|
+
throw new BadDataException(
|
|
110
|
+
"Webhook URL points to a private, loopback, or link-local address and is not allowed.",
|
|
111
|
+
);
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
if (!SSRFProtection.isIpLiteral(hostname)) {
|
|
115
|
+
let resolved: Array<{ address: string }> = [];
|
|
116
|
+
try {
|
|
117
|
+
resolved = await dns.promises.lookup(hostname, { all: true });
|
|
118
|
+
} catch {
|
|
119
|
+
throw new BadDataException(
|
|
120
|
+
"Webhook URL hostname could not be resolved via DNS.",
|
|
121
|
+
);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
for (const entry of resolved) {
|
|
125
|
+
if (
|
|
126
|
+
SSRFProtection.isBlockedHostnameLiteral(entry.address.toLowerCase())
|
|
127
|
+
) {
|
|
128
|
+
throw new BadDataException(
|
|
129
|
+
"Webhook URL resolves to a private, loopback, or link-local address and is not allowed.",
|
|
130
|
+
);
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/*
|
|
137
|
+
* Extracts the bare host (IPv4, IPv6, or hostname) from a "host[:port]"
|
|
138
|
+
* string, handling bracketed IPv6 (`[::1]`, `[::1]:8080`) and unbracketed
|
|
139
|
+
* IPv6 literals (which contain multiple colons and carry no port).
|
|
140
|
+
*/
|
|
141
|
+
private static extractHost(hostWithPort: string): string {
|
|
142
|
+
const host: string = hostWithPort.trim();
|
|
143
|
+
|
|
144
|
+
if (host.startsWith("[")) {
|
|
145
|
+
const closingBracketIndex: number = host.indexOf("]");
|
|
146
|
+
if (closingBracketIndex !== -1) {
|
|
147
|
+
return host.slice(1, closingBracketIndex);
|
|
148
|
+
}
|
|
149
|
+
return host.replace(/^\[|\]$/g, "");
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
const colonCount: number = (host.match(/:/g) || []).length;
|
|
153
|
+
|
|
154
|
+
if (colonCount > 1) {
|
|
155
|
+
// Unbracketed IPv6 literal — colons are part of the address, not a port.
|
|
156
|
+
return host;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
if (colonCount === 1) {
|
|
160
|
+
// host:port — keep only the host part.
|
|
161
|
+
return host.split(":")[0] || "";
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
return host;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
private static isIpLiteral(hostname: string): boolean {
|
|
168
|
+
return IPV4_LITERAL_REGEX.test(hostname) || hostname.includes(":");
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
private static isBlockedHostnameLiteral(hostname: string): boolean {
|
|
172
|
+
if (
|
|
173
|
+
hostname === "localhost" ||
|
|
174
|
+
hostname.endsWith(".localhost") ||
|
|
175
|
+
hostname === "metadata.google.internal"
|
|
176
|
+
) {
|
|
177
|
+
return true;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
const ipv4Match: RegExpMatchArray | null = hostname.match(
|
|
181
|
+
/^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/,
|
|
182
|
+
);
|
|
183
|
+
if (ipv4Match) {
|
|
184
|
+
const octets: Array<number> = [
|
|
185
|
+
Number(ipv4Match[1]),
|
|
186
|
+
Number(ipv4Match[2]),
|
|
187
|
+
Number(ipv4Match[3]),
|
|
188
|
+
Number(ipv4Match[4]),
|
|
189
|
+
];
|
|
190
|
+
|
|
191
|
+
if (
|
|
192
|
+
octets.some((o: number) => {
|
|
193
|
+
return o < 0 || o > 255;
|
|
194
|
+
})
|
|
195
|
+
) {
|
|
196
|
+
return true;
|
|
197
|
+
}
|
|
198
|
+
if (octets[0] === 0) {
|
|
199
|
+
return true;
|
|
200
|
+
}
|
|
201
|
+
if (octets[0] === 127) {
|
|
202
|
+
return true;
|
|
203
|
+
}
|
|
204
|
+
if (octets[0] === 10) {
|
|
205
|
+
return true;
|
|
206
|
+
}
|
|
207
|
+
if (octets[0] === 172 && (octets[1]! & 0xf0) === 16) {
|
|
208
|
+
return true;
|
|
209
|
+
}
|
|
210
|
+
if (octets[0] === 192 && octets[1] === 168) {
|
|
211
|
+
return true;
|
|
212
|
+
}
|
|
213
|
+
if (octets[0] === 169 && octets[1] === 254) {
|
|
214
|
+
return true;
|
|
215
|
+
}
|
|
216
|
+
if (octets[0] === 100 && (octets[1]! & 0xc0) === 64) {
|
|
217
|
+
return true;
|
|
218
|
+
}
|
|
219
|
+
return false;
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
if (hostname.includes(":")) {
|
|
223
|
+
const stripped: string = hostname.replace(/^\[|\]$/g, "");
|
|
224
|
+
if (stripped === "::1" || stripped === "::") {
|
|
225
|
+
return true;
|
|
226
|
+
}
|
|
227
|
+
if (stripped.startsWith("fe80:") || stripped.startsWith("fe80::")) {
|
|
228
|
+
return true;
|
|
229
|
+
}
|
|
230
|
+
if (IPV6_UNIQUE_LOCAL_REGEX.test(stripped)) {
|
|
231
|
+
return true;
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
return false;
|
|
236
|
+
}
|
|
237
|
+
}
|
|
@@ -34,6 +34,7 @@ import "./Process";
|
|
|
34
34
|
import Response from "./Response";
|
|
35
35
|
import SpanUtil from "./Telemetry/SpanUtil";
|
|
36
36
|
import TelemetryContext from "./Telemetry/TelemetryContext";
|
|
37
|
+
import mountVendorAssets from "./VendorAssets";
|
|
37
38
|
import { api } from "@opentelemetry/sdk-node";
|
|
38
39
|
import StatusCode from "../../Types/API/StatusCode";
|
|
39
40
|
import HTTPErrorResponse from "../../Types/API/HTTPErrorResponse";
|
|
@@ -303,6 +304,13 @@ const init: InitFunction = async (
|
|
|
303
304
|
statusOptions: data.statusOptions,
|
|
304
305
|
});
|
|
305
306
|
|
|
307
|
+
/*
|
|
308
|
+
* Ahead of the frontend static mounts and every catch-all below them, so a
|
|
309
|
+
* service that answers "/*" with its index page cannot swallow a request for
|
|
310
|
+
* a stylesheet.
|
|
311
|
+
*/
|
|
312
|
+
mountVendorAssets(app);
|
|
313
|
+
|
|
306
314
|
if (isFrontendApp) {
|
|
307
315
|
app.use(ExpressStatic("/usr/src/app/public"));
|
|
308
316
|
|
|
@@ -4,6 +4,7 @@ import HTTPErrorResponse from "../../Types/API/HTTPErrorResponse";
|
|
|
4
4
|
import HTTPResponse from "../../Types/API/HTTPResponse";
|
|
5
5
|
import { JSONObject } from "../../Types/JSON";
|
|
6
6
|
import logger from "./Logger";
|
|
7
|
+
import SSRFProtection from "./SSRFProtection";
|
|
7
8
|
|
|
8
9
|
export interface StatusPageWebhookPayload extends JSONObject {
|
|
9
10
|
eventType: string;
|
|
@@ -21,6 +22,30 @@ export default class StatusPageSubscriberWebhookUtil {
|
|
|
21
22
|
}): Promise<HTTPResponse<JSONObject> | HTTPErrorResponse> {
|
|
22
23
|
logger.debug("Sending status page subscriber webhook notification.");
|
|
23
24
|
|
|
25
|
+
/*
|
|
26
|
+
* The subscriber webhook target is attacker-controllable: any unauthenticated
|
|
27
|
+
* visitor can register a subscriber with an arbitrary webhook URL on a public
|
|
28
|
+
* status page. Validate it against the SSRF blocklist before every send (not
|
|
29
|
+
* just at create time) so previously-stored URLs and DNS-rebinding cannot make
|
|
30
|
+
* the server reach internal services or the cloud metadata endpoint.
|
|
31
|
+
*/
|
|
32
|
+
try {
|
|
33
|
+
await SSRFProtection.validateWebhookTargetIsSafe(data.webhookUrl);
|
|
34
|
+
} catch (err) {
|
|
35
|
+
logger.warn(
|
|
36
|
+
"Refusing to send status page subscriber webhook: unsafe URL.",
|
|
37
|
+
);
|
|
38
|
+
logger.warn(err);
|
|
39
|
+
return new HTTPErrorResponse(
|
|
40
|
+
400,
|
|
41
|
+
{
|
|
42
|
+
message:
|
|
43
|
+
err instanceof Error ? err.message : "Webhook URL is not allowed.",
|
|
44
|
+
},
|
|
45
|
+
{},
|
|
46
|
+
);
|
|
47
|
+
}
|
|
48
|
+
|
|
24
49
|
const apiResult: HTTPResponse<JSONObject> | HTTPErrorResponse =
|
|
25
50
|
await API.post({
|
|
26
51
|
url: data.webhookUrl,
|
|
@@ -28,6 +53,11 @@ export default class StatusPageSubscriberWebhookUtil {
|
|
|
28
53
|
options: {
|
|
29
54
|
retries: 3,
|
|
30
55
|
exponentialBackoff: true,
|
|
56
|
+
/*
|
|
57
|
+
* Do not follow redirects: a validated public host could otherwise
|
|
58
|
+
* 3xx-redirect the server to an internal address, bypassing the check.
|
|
59
|
+
*/
|
|
60
|
+
doNotFollowRedirects: true,
|
|
31
61
|
},
|
|
32
62
|
});
|
|
33
63
|
|
|
@@ -38,35 +38,47 @@ function CaptureSpan(data?: {
|
|
|
38
38
|
data?.name || `${className}.${propertyKey}`;
|
|
39
39
|
|
|
40
40
|
descriptor.value = function (...args: any[]) {
|
|
41
|
-
|
|
41
|
+
/*
|
|
42
|
+
* Skip the span machinery entirely when telemetry is disabled OR no
|
|
43
|
+
* span exporter is installed. Without an exporter the span is never
|
|
44
|
+
* shipped anywhere, but creating it still costs attribute flattening,
|
|
45
|
+
* a span allocation, and an AsyncLocalStorage context transition —
|
|
46
|
+
* decorated methods sit on ingest hot paths that run millions of
|
|
47
|
+
* times per minute, so this must be a plain method call there.
|
|
48
|
+
*/
|
|
49
|
+
if (DisableTelemetry || !Telemetry.isSpanExportEnabled()) {
|
|
42
50
|
return originalMethod.apply(this, args);
|
|
43
51
|
}
|
|
44
52
|
|
|
45
|
-
|
|
53
|
+
/*
|
|
54
|
+
* Only pay for attribute flattening when there is something to
|
|
55
|
+
* flatten — the overwhelmingly common bare @CaptureSpan() form has
|
|
56
|
+
* neither captured arguments nor static attributes.
|
|
57
|
+
*/
|
|
58
|
+
let spanAttributes: { [key: string]: any } | undefined = undefined;
|
|
46
59
|
|
|
47
|
-
if (data?.captureArguments) {
|
|
48
|
-
functionArguments =
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
60
|
+
if (data?.captureArguments || data?.attributes) {
|
|
61
|
+
let functionArguments: JSONObject = {};
|
|
62
|
+
|
|
63
|
+
if (data?.captureArguments) {
|
|
64
|
+
functionArguments = args.reduce(
|
|
65
|
+
(acc: { [key: string]: any }, arg: any, index: number) => {
|
|
66
|
+
acc[`arg${index}`] = arg;
|
|
67
|
+
return acc;
|
|
68
|
+
},
|
|
69
|
+
{},
|
|
70
|
+
);
|
|
71
|
+
}
|
|
56
72
|
|
|
57
|
-
|
|
58
|
-
JSONFunctions.flattenObject({
|
|
73
|
+
spanAttributes = JSONFunctions.flattenObject({
|
|
59
74
|
...functionArguments,
|
|
60
75
|
...data?.attributes,
|
|
61
76
|
}) as { [key: string]: any };
|
|
77
|
+
}
|
|
62
78
|
|
|
63
79
|
return Telemetry.startActiveSpan({
|
|
64
80
|
name: name,
|
|
65
|
-
options: {
|
|
66
|
-
attributes: {
|
|
67
|
-
...spanAttributes,
|
|
68
|
-
},
|
|
69
|
-
},
|
|
81
|
+
options: spanAttributes ? { attributes: spanAttributes } : {},
|
|
70
82
|
fn: (span: Span) => {
|
|
71
83
|
let result: any = null;
|
|
72
84
|
try {
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import OneUptimeDate from "../../../Types/Date";
|
|
2
|
+
|
|
3
|
+
/*
|
|
4
|
+
* Per-second memo for the wall-clock stamps every ingested telemetry row
|
|
5
|
+
* carries (createdAt and retentionDate, both stored with second
|
|
6
|
+
* granularity).
|
|
7
|
+
*
|
|
8
|
+
* The Otel logs / traces / metrics row builders used to derive these per
|
|
9
|
+
* row: a current-Date allocation, a ClickHouse DateTime format, a
|
|
10
|
+
* moment-based add-days, and a second format — for every log record, span,
|
|
11
|
+
* and metric datapoint. All of that output only changes once per second
|
|
12
|
+
* (createdAt has no sub-second component) and once per distinct retention
|
|
13
|
+
* window, so a burst of rows in the same second re-derived identical
|
|
14
|
+
* strings millions of times. This memo pays the derivation once per second
|
|
15
|
+
* (and once per retention window within that second) instead.
|
|
16
|
+
*
|
|
17
|
+
* Not thread-shared state to worry about: workers are single-threaded, and
|
|
18
|
+
* the memo is replaced wholesale when the second rolls over, so the map of
|
|
19
|
+
* retention strings can never grow past the number of distinct retention
|
|
20
|
+
* windows seen within one second.
|
|
21
|
+
*/
|
|
22
|
+
|
|
23
|
+
export interface IngestionStamp {
|
|
24
|
+
/** Current time truncated to the second the stamp was minted. */
|
|
25
|
+
date: Date;
|
|
26
|
+
/** ClickHouse DateTime string ("YYYY-MM-DD HH:mm:ss", UTC) of `date`. */
|
|
27
|
+
db: string;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
type CachedStamp = IngestionStamp & {
|
|
31
|
+
epochSecond: number;
|
|
32
|
+
retentionDbByDays: Map<number, string>;
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
let cachedStamp: CachedStamp | null = null;
|
|
36
|
+
|
|
37
|
+
export function getIngestionStamp(): IngestionStamp {
|
|
38
|
+
const epochSecond: number = Math.floor(Date.now() / 1000);
|
|
39
|
+
|
|
40
|
+
if (!cachedStamp || cachedStamp.epochSecond !== epochSecond) {
|
|
41
|
+
const date: Date = new Date(epochSecond * 1000);
|
|
42
|
+
cachedStamp = {
|
|
43
|
+
epochSecond: epochSecond,
|
|
44
|
+
date: date,
|
|
45
|
+
db: OneUptimeDate.toClickhouseDateTime(date),
|
|
46
|
+
retentionDbByDays: new Map<number, string>(),
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
return cachedStamp;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/*
|
|
54
|
+
* ClickHouse DateTime string for `stamp.date + retentionDays`, memoized per
|
|
55
|
+
* (stamp second, retention window). Must be called with a stamp obtained
|
|
56
|
+
* from getIngestionStamp() in the same row-building pass, so the retention
|
|
57
|
+
* date stays consistent with the row's createdAt.
|
|
58
|
+
*/
|
|
59
|
+
export function getRetentionDateDb(
|
|
60
|
+
stamp: IngestionStamp,
|
|
61
|
+
retentionDays: number,
|
|
62
|
+
): string {
|
|
63
|
+
const cached: CachedStamp = stamp as CachedStamp;
|
|
64
|
+
|
|
65
|
+
let db: string | undefined = cached.retentionDbByDays?.get(retentionDays);
|
|
66
|
+
|
|
67
|
+
if (db === undefined) {
|
|
68
|
+
db = OneUptimeDate.toClickhouseDateTime(
|
|
69
|
+
OneUptimeDate.addRemoveDays(stamp.date, retentionDays),
|
|
70
|
+
);
|
|
71
|
+
cached.retentionDbByDays?.set(retentionDays, db);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
return db;
|
|
75
|
+
}
|