From c77437b76b68cec7b54f7b1a90eff6efff37b8e2 Mon Sep 17 00:00:00 2001 From: Adrian Elder Date: Fri, 27 Mar 2026 22:49:32 -0400 Subject: [PATCH 1/2] fix: Enable detekt rule: ConstructorParameterNaming (automated) --- backend/detekt.yml | 2 +- .../src/main/kotlin/com/moneat/ai/AiModels.kt | 17 +- .../main/kotlin/com/moneat/ai/OpenAiClient.kt | 4 +- .../com/moneat/auth/services/OAuthService.kt | 7 +- .../com/moneat/events/models/SentryModels.kt | 48 ++--- .../events/services/DashboardQueryHelper.kt | 4 +- .../moneat/events/services/EventService.kt | 137 +++++++++----- .../incident/services/IncidentIoProvider.kt | 14 +- .../moneat/monitor/models/MonitorModels.kt | 96 +++++----- .../moneat/monitor/routes/MonitorRoutes.kt | 16 +- .../moneat/monitor/services/MonitorService.kt | 172 +++++++++--------- .../notifications/services/DiscordService.kt | 5 +- .../notifications/services/SlackService.kt | 17 +- .../moneat/org/routes/IntegrationRoutes.kt | 16 +- .../shared/services/SdkVersionService.kt | 5 +- .../moneat/summary/services/SummaryService.kt | 20 +- .../kotlin/com/moneat/ai/AiChatServiceTest.kt | 4 +- .../models/SentryTimestampParsingTest.kt | 6 +- .../moneat/routes/MonitorRoutesMockTest.kt | 24 +-- .../services/DiscordServiceBuildersTest.kt | 2 +- .../services/EventServiceCoverageTest.kt | 140 +++++++------- .../com/moneat/services/EventServiceTest.kt | 18 +- .../services/MonitorServiceExtendedTest.kt | 78 ++++---- .../services/NotificationFormattingTest.kt | 14 +- .../NotificationServiceRoutingTest.kt | 10 +- .../services/NotificationServiceTest.kt | 4 +- .../com/moneat/services/SummaryServiceTest.kt | 30 +-- ee/backend/detekt.yml | 2 +- .../ai/llm/providers/AnthropicProvider.kt | 13 +- .../ai/llm/providers/OpenAiProvider.kt | 24 ++- .../enterprise/mcp/services/SummaryService.kt | 4 +- 31 files changed, 509 insertions(+), 444 deletions(-) diff --git a/backend/detekt.yml b/backend/detekt.yml index cd496cad4..833a8c8b2 100644 --- a/backend/detekt.yml +++ b/backend/detekt.yml @@ -66,7 +66,7 @@ naming: MatchingDeclarationName: active: true ConstructorParameterNaming: - active: false + active: true FunctionNaming: active: true excludes: diff --git a/backend/src/main/kotlin/com/moneat/ai/AiModels.kt b/backend/src/main/kotlin/com/moneat/ai/AiModels.kt index 1baa6b89f..60e8ee10f 100644 --- a/backend/src/main/kotlin/com/moneat/ai/AiModels.kt +++ b/backend/src/main/kotlin/com/moneat/ai/AiModels.kt @@ -16,6 +16,7 @@ package com.moneat.ai +import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable import org.jetbrains.exposed.v1.core.Table import org.jetbrains.exposed.v1.datetime.timestamp @@ -99,9 +100,9 @@ data class AiResponse( val message: String = "", val actions: List = emptyList(), val clarifications: List = emptyList(), - val data_queries: List = emptyList(), + @SerialName("data_queries") val dataQueries: List = emptyList(), val links: List = emptyList(), - val context_needed: List = emptyList() + @SerialName("context_needed") val contextNeeded: List = emptyList() ) @Serializable @@ -166,9 +167,9 @@ data class ActionResult( data class OpenAiChatRequest( val model: String, val messages: List, - val max_tokens: Int = 2048, + @SerialName("max_tokens") val maxTokens: Int = 2048, val temperature: Double = 0.3, - val response_format: OpenAiResponseFormat? = null + @SerialName("response_format") val responseFormat: OpenAiResponseFormat? = null ) @Serializable @@ -192,12 +193,12 @@ data class OpenAiChatResponse( @Serializable data class OpenAiChoice( val message: OpenAiMessage, - val finish_reason: String? = null + @SerialName("finish_reason") val finishReason: String? = null ) @Serializable data class OpenAiUsage( - val prompt_tokens: Int = 0, - val completion_tokens: Int = 0, - val total_tokens: Int = 0 + @SerialName("prompt_tokens") val promptTokens: Int = 0, + @SerialName("completion_tokens") val completionTokens: Int = 0, + @SerialName("total_tokens") val totalTokens: Int = 0 ) diff --git a/backend/src/main/kotlin/com/moneat/ai/OpenAiClient.kt b/backend/src/main/kotlin/com/moneat/ai/OpenAiClient.kt index 92f5aeb2b..37a619b70 100644 --- a/backend/src/main/kotlin/com/moneat/ai/OpenAiClient.kt +++ b/backend/src/main/kotlin/com/moneat/ai/OpenAiClient.kt @@ -72,9 +72,9 @@ object OpenAiClient { OpenAiChatRequest( model = model, messages = messages, - max_tokens = maxTokens, + maxTokens = maxTokens, temperature = 0.3, - response_format = OpenAiResponseFormat(type = "json_object") + responseFormat = OpenAiResponseFormat(type = "json_object") ) val response = diff --git a/backend/src/main/kotlin/com/moneat/auth/services/OAuthService.kt b/backend/src/main/kotlin/com/moneat/auth/services/OAuthService.kt index d23598a11..ac0ad01ea 100644 --- a/backend/src/main/kotlin/com/moneat/auth/services/OAuthService.kt +++ b/backend/src/main/kotlin/com/moneat/auth/services/OAuthService.kt @@ -37,6 +37,7 @@ import io.ktor.http.HttpHeaders import io.ktor.http.encodeURLParameter import io.ktor.serialization.kotlinx.json.json import io.ktor.server.config.ApplicationConfig +import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable import kotlinx.serialization.json.Json import mu.KotlinLogging @@ -56,8 +57,8 @@ private val logger = KotlinLogging.logger {} @Serializable data class GitHubAccessTokenResponse( - val access_token: String, - val token_type: String, + @SerialName("access_token") val accessToken: String, + @SerialName("token_type") val tokenType: String, val scope: String ) @@ -174,7 +175,7 @@ class OAuthService { } val tokenData: GitHubAccessTokenResponse = tokenResponse.body() - val accessToken = tokenData.access_token + val accessToken = tokenData.accessToken // Fetch user info val userResponse: HttpResponse = diff --git a/backend/src/main/kotlin/com/moneat/events/models/SentryModels.kt b/backend/src/main/kotlin/com/moneat/events/models/SentryModels.kt index c265dbb72..02ca9ee62 100644 --- a/backend/src/main/kotlin/com/moneat/events/models/SentryModels.kt +++ b/backend/src/main/kotlin/com/moneat/events/models/SentryModels.kt @@ -17,6 +17,7 @@ package com.moneat.events.models import kotlinx.serialization.KSerializer +import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable import kotlinx.serialization.SerializationException import kotlinx.serialization.descriptors.PrimitiveKind @@ -195,7 +196,7 @@ data class EnvelopeItem( @Serializable data class SentryEvent( - val event_id: String? = null, + @SerialName("event_id") val eventId: String? = null, @Serializable(with = FlexibleTimestampSerializer::class) val timestamp: Double? = null, val level: String? = null, @@ -215,7 +216,7 @@ data class SentryEvent( val breadcrumbs: JsonArray? = null, val request: JsonObject? = null, val fingerprint: List? = null, - val server_name: String? = null, + @SerialName("server_name") val serverName: String? = null, val threads: JsonObject? = null ) @@ -323,11 +324,12 @@ object FlexibleTimestampSerializer : KSerializer { @Serializable data class SentryTransaction( - val event_id: String? = null, + @SerialName("event_id") val eventId: String? = null, val type: String? = null, val transaction: String? = null, @Serializable(with = FlexibleTimestampSerializer::class) - val start_timestamp: Double? = null, + @SerialName("start_timestamp") + val startTimestamp: Double? = null, @Serializable(with = FlexibleTimestampSerializer::class) val timestamp: Double? = null, val platform: String? = null, @@ -339,7 +341,7 @@ data class SentryTransaction( val contexts: JsonObject? = null, val spans: List? = null, val sdk: SdkInfo? = null, - val server_name: String? = null, + @SerialName("server_name") val serverName: String? = null, val request: JsonObject? = null, @Serializable(with = BreadcrumbsSerializer::class) val breadcrumbs: JsonArray? = null, @@ -348,13 +350,14 @@ data class SentryTransaction( @Serializable data class SentrySpan( - val span_id: String? = null, - val parent_span_id: String? = null, - val trace_id: String? = null, + @SerialName("span_id") val spanId: String? = null, + @SerialName("parent_span_id") val parentSpanId: String? = null, + @SerialName("trace_id") val traceId: String? = null, val op: String? = null, val description: String? = null, @Serializable(with = FlexibleTimestampSerializer::class) - val start_timestamp: Double? = null, + @SerialName("start_timestamp") + val startTimestamp: Double? = null, @Serializable(with = FlexibleTimestampSerializer::class) val timestamp: Double? = null, val status: String? = null, @@ -393,11 +396,11 @@ data class StackFrame( val module: String? = null, val lineno: Int? = null, val colno: Int? = null, - val abs_path: String? = null, - val context_line: String? = null, - val pre_context: List? = null, - val post_context: List? = null, - val in_app: Boolean? = null, + @SerialName("abs_path") val absPath: String? = null, + @SerialName("context_line") val contextLine: String? = null, + @SerialName("pre_context") val preContext: List? = null, + @SerialName("post_context") val postContext: List? = null, + @SerialName("in_app") val inApp: Boolean? = null, val vars: JsonObject? = null ) @@ -406,20 +409,21 @@ data class UserInfo( val id: String? = null, val email: String? = null, val username: String? = null, - val ip_address: String? = null + @SerialName("ip_address") val ipAddress: String? = null ) @Serializable data class SentryReplayEvent( - val replay_id: String? = null, - val segment_id: Int? = null, + @SerialName("replay_id") val replayId: String? = null, + @SerialName("segment_id") val segmentId: Int? = null, @Serializable(with = FlexibleTimestampSerializer::class) val timestamp: Double? = null, @Serializable(with = FlexibleTimestampSerializer::class) - val replay_start_timestamp: Double? = null, + @SerialName("replay_start_timestamp") + val replayStartTimestamp: Double? = null, val urls: List? = null, - val error_ids: List? = null, - val trace_ids: List? = null, + @SerialName("error_ids") val errorIds: List? = null, + @SerialName("trace_ids") val traceIds: List? = null, val platform: String? = null, val environment: String? = null, val release: String? = null, @@ -427,12 +431,12 @@ data class SentryReplayEvent( val contexts: JsonObject? = null, val sdk: SdkInfo? = null, val tags: Map? = null, - val replay_type: String? = null + @SerialName("replay_type") val replayType: String? = null ) @Serializable data class SentryFeedback( - val event_id: String? = null, + @SerialName("event_id") val eventId: String? = null, val timestamp: String? = null, val platform: String? = null, val level: String? = null, diff --git a/backend/src/main/kotlin/com/moneat/events/services/DashboardQueryHelper.kt b/backend/src/main/kotlin/com/moneat/events/services/DashboardQueryHelper.kt index 281b29b68..c67ef0fc1 100644 --- a/backend/src/main/kotlin/com/moneat/events/services/DashboardQueryHelper.kt +++ b/backend/src/main/kotlin/com/moneat/events/services/DashboardQueryHelper.kt @@ -177,7 +177,7 @@ class DashboardQueryHelper( val userEmail = obj["user_email"]?.jsonPrimitive?.contentOrNull val userUsername = obj["user_username"]?.jsonPrimitive?.contentOrNull return if (userId != null || userEmail != null || userUsername != null) { - UserInfo(id = userId, email = userEmail, username = userUsername, ip_address = null) + UserInfo(id = userId, email = userEmail, username = userUsername, ipAddress = null) } else { null } @@ -213,7 +213,7 @@ class DashboardQueryHelper( } fun parseTraceContext(contexts: String): JsonObject? { - return suspendRunCatching { + return runCatching { val contextsJson = json.parseToJsonElement(contexts) as? JsonObject ?: return null contextsJson["trace"] as? JsonObject }.getOrElse { _ -> diff --git a/backend/src/main/kotlin/com/moneat/events/services/EventService.kt b/backend/src/main/kotlin/com/moneat/events/services/EventService.kt index a06f0c5c2..fd5e3eaeb 100644 --- a/backend/src/main/kotlin/com/moneat/events/services/EventService.kt +++ b/backend/src/main/kotlin/com/moneat/events/services/EventService.kt @@ -162,8 +162,8 @@ class EventService( "replay_event" -> { val replayEvent = parseReplayEventPayload(item.payload) - lastReplayId = replayEvent.replay_id - lastSegmentId = replayEvent.segment_id ?: 0 + lastReplayId = replayEvent.replayId + lastSegmentId = replayEvent.segmentId ?: 0 if (storeReplayEvent(projectId, replayEvent)) { recordUsage(projectId, "replay", item) } @@ -254,7 +254,7 @@ class EventService( projectId: Long, transaction: SentryTransaction ): Boolean { - val rawEventId = transaction.event_id ?: UUID.randomUUID().toString() + val rawEventId = transaction.eventId ?: UUID.randomUUID().toString() val eventId = normalizeUuid(rawEventId) val traceContext = transaction.contexts?.get("trace") as? JsonObject val traceId = traceContext?.get("trace_id")?.jsonPrimitive?.contentOrNull ?: "" @@ -263,7 +263,7 @@ class EventService( val transactionLevel = if (traceStatus == null || traceStatus == "ok") "info" else "error" val endTimestampMs = unixSecondsToMillis(transaction.timestamp ?: (System.currentTimeMillis() / 1000.0)) - val durationMs = durationMs(transaction.start_timestamp, transaction.timestamp) + val durationMs = durationMs(transaction.startTimestamp, transaction.timestamp) val contexts = transaction.contexts?.toString() ?: "{}" val breadcrumbs = transaction.breadcrumbs?.toString() ?: "[]" @@ -280,11 +280,11 @@ class EventService( environment = transaction.environment ?: "production", release = transaction.release ?: "", dist = transaction.dist ?: "", - serverName = transaction.server_name ?: "", + serverName = transaction.serverName ?: "", userId = transaction.user?.id ?: "", userEmail = transaction.user?.email ?: "", userUsername = transaction.user?.username ?: "", - userIpAddress = transaction.user?.ip_address ?: "", + userIpAddress = transaction.user?.ipAddress ?: "", transactionName = transaction.transaction ?: "", transactionOp = transactionOp, durationMs = durationMs, @@ -343,7 +343,7 @@ class EventService( projectId: Long, event: SentryEvent ): Boolean { - val eventId = event.event_id ?: UUID.randomUUID().toString() + val eventId = event.eventId ?: UUID.randomUUID().toString() logger.debug { "Full event structure - exception: ${event.exception}, message: ${event.message}, " + @@ -400,11 +400,11 @@ class EventService( environment = event.environment ?: "production", release = event.release ?: "", dist = event.dist ?: "", - serverName = event.server_name ?: "", + serverName = event.serverName ?: "", userId = event.user?.id ?: "", userEmail = event.user?.email ?: "", userUsername = event.user?.username ?: "", - userIpAddress = event.user?.ip_address ?: "", + userIpAddress = event.user?.ipAddress ?: "", exceptionType = exceptionType, exceptionValue = exceptionValue, stackTrace = stackTrace, @@ -459,7 +459,7 @@ class EventService( return false } - val feedbackId = feedback.event_id ?: UUID.randomUUID().toString() + val feedbackId = feedback.eventId ?: UUID.randomUUID().toString() val timestamp = feedback.timestamp?.let { suspendRunCatching { @@ -483,7 +483,7 @@ class EventService( val userId = feedback.user?.id ?: "" val userEmail = feedback.user?.email ?: contactEmail val userUsername = feedback.user?.username ?: "" - val userIpAddress = feedback.user?.ip_address ?: "" + val userIpAddress = feedback.user?.ipAddress ?: "" val feedbackData = FeedbackInsertData( feedbackId = normalizeUuid(feedbackId), @@ -528,14 +528,14 @@ class EventService( return false } - val replayId = replayEvent.replay_id ?: UUID.randomUUID().toString() - val segmentId = replayEvent.segment_id ?: 0 + val replayId = replayEvent.replayId ?: UUID.randomUUID().toString() + val segmentId = replayEvent.segmentId ?: 0 val ts = replayEvent.timestamp?.let { unixSecondsToMillis(it) } ?: System.currentTimeMillis() - val startTs = replayEvent.replay_start_timestamp?.let { unixSecondsToMillis(it) } ?: ts + val startTs = replayEvent.replayStartTimestamp?.let { unixSecondsToMillis(it) } ?: ts val urls = replayEvent.urls?.take(100) ?: emptyList() - val errorIds = replayEvent.error_ids ?: emptyList() - val traceIds = replayEvent.trace_ids ?: emptyList() + val errorIds = replayEvent.errorIds ?: emptyList() + val traceIds = replayEvent.traceIds ?: emptyList() val tags = replayEvent.tags?.let { JsonObject(it.mapValues { (_, v) -> JsonPrimitive(v) }).toString() } ?: "{}" val contexts = replayEvent.contexts @@ -571,7 +571,7 @@ class EventService( userId = replayEvent.user?.id ?: "", userEmail = replayEvent.user?.email ?: "", userUsername = replayEvent.user?.username ?: "", - userIpAddress = replayEvent.user?.ip_address ?: "", + userIpAddress = replayEvent.user?.ipAddress ?: "", sdkName = replayEvent.sdk?.name ?: "", sdkVersion = replayEvent.sdk?.version ?: "", browserName = browserName, @@ -617,11 +617,64 @@ class EventService( } } + private data class SyntheticReplayMetadata( + val sdkName: String, + val sdkVersion: String, + val platform: String, + val environment: String, + val release: String, + ) + + private fun syntheticReplayMetadataFromEnvelope(envelope: SentryEnvelope): SyntheticReplayMetadata { + val fallback = SyntheticReplayMetadata( + sdkName = "sentry.java.android", + sdkVersion = "", + platform = "android", + environment = "e2e-testing", + release = "", + ) + for (item in envelope.items) { + when (item.type) { + "replay_event" -> { + val re = runCatching { parseReplayEventPayload(item.payload) }.getOrNull() ?: continue + return SyntheticReplayMetadata( + sdkName = re.sdk?.name ?: fallback.sdkName, + sdkVersion = re.sdk?.version ?: "", + platform = re.platform ?: fallback.platform, + environment = re.environment ?: fallback.environment, + release = re.release ?: "", + ) + } + "event" -> { + val ev = runCatching { json.decodeFromString(item.payload) }.getOrNull() ?: continue + return SyntheticReplayMetadata( + sdkName = ev.sdk?.name ?: fallback.sdkName, + sdkVersion = ev.sdk?.version ?: "", + platform = ev.platform ?: fallback.platform, + environment = ev.environment ?: fallback.environment, + release = ev.release ?: "", + ) + } + "transaction" -> { + val tx = runCatching { parseTransactionPayload(item.payload) }.getOrNull() ?: continue + return SyntheticReplayMetadata( + sdkName = tx.sdk?.name ?: fallback.sdkName, + sdkVersion = tx.sdk?.version ?: "", + platform = tx.platform ?: fallback.platform, + environment = tx.environment ?: fallback.environment, + release = tx.release ?: "", + ) + } + } + } + return fallback + } + private suspend fun storeSyntheticReplayEvent( projectId: Long, replayId: String, segmentId: Int, - @Suppress("UNUSED_PARAMETER") envelope: SentryEnvelope + envelope: SentryEnvelope ) { // Validate project ID — allow negative demo project IDs (-1, -2, -3) if (projectId == 0L) { @@ -631,11 +684,7 @@ class EventService( val normalizedReplayId = normalizeUuid(replayId) val timestamp = System.currentTimeMillis() - - // Extract SDK info from envelope header if available - val sdkName = "sentry.java.android" - val sdkVersion = "" - val platform = "android" + val meta = syntheticReplayMetadataFromEnvelope(envelope) suspendRunCatching { eventRepository.insertReplayEvent( @@ -648,15 +697,15 @@ class EventService( urls = emptyList(), errorIds = emptyList(), traceIds = emptyList(), - environment = "e2e-testing", - release = "", - platform = platform, + environment = meta.environment, + release = meta.release, + platform = meta.platform, userId = "", userEmail = "", userUsername = "", userIpAddress = "", - sdkName = sdkName, - sdkVersion = sdkVersion, + sdkName = meta.sdkName, + sdkVersion = meta.sdkVersion, browserName = "", browserVersion = "", osName = "", @@ -782,13 +831,13 @@ class EventService( // Find the last in_app frame (innermost/actual error location), or fall back to the last frame val relevantFrame = - firstException?.stacktrace?.frames?.findLast { it.in_app == true } + firstException?.stacktrace?.frames?.findLast { it.inApp == true } ?: firstException?.stacktrace?.frames?.lastOrNull() val function = relevantFrame?.function val filename = relevantFrame?.filename - logger.trace { "Selected frame: filename=$filename, function=$function, in_app=${relevantFrame?.in_app}" } + logger.trace { "Selected frame: filename=$filename, function=$function, in_app=${relevantFrame?.inApp}" } val fingerprint = buildList { @@ -836,7 +885,7 @@ class EventService( ) { suspendRunCatching { val generations = aiSpans.mapNotNull { span -> - val spanStart = span.start_timestamp ?: return@mapNotNull null + val spanStart = span.startTimestamp ?: return@mapNotNull null val spanEnd = span.timestamp ?: return@mapNotNull null val op = span.op ?: "" val data = span.data @@ -864,8 +913,8 @@ class EventService( generationId = UUID.randomUUID().toString(), projectId = projectId, traceId = traceId, - spanId = span.span_id ?: "", - parentSpanId = span.parent_span_id ?: "", + spanId = span.spanId ?: "", + parentSpanId = span.parentSpanId ?: "", timestampMs = unixSecondsToMillis(spanEnd), durationMs = durationMs(spanStart, spanEnd), name = span.description ?: op, @@ -967,10 +1016,10 @@ class EventService( val ctx = ApmSpanContext( orgId = orgId, clickhouseDb = ClickHouseClient.getDatabase(), - service = transaction.server_name?.takeIf { it.isNotBlank() } + service = transaction.serverName?.takeIf { it.isNotBlank() } ?: transaction.sdk?.name?.takeIf { it.isNotBlank() } ?: "sentry", - host = transaction.server_name ?: "", + host = transaction.serverName ?: "", env = transaction.environment ?: "production", version = transaction.release ?: "", transactionName = transaction.transaction ?: transactionOp.ifBlank { "transaction" }, @@ -999,7 +1048,7 @@ class EventService( ?.get("span_id")?.jsonPrimitive?.contentOrNull ?: "" if (rootSpanId.isBlank()) return null - val startTs = transaction.start_timestamp ?: (System.currentTimeMillis() / 1000.0) + val startTs = transaction.startTimestamp ?: (System.currentTimeMillis() / 1000.0) val (traceIdHigh, traceIdLow) = hexToULongPair(traceId) val (spanIdHigh, spanIdLow) = hexToULongPair(rootSpanId) val rootMetrics = extractMeasurementMetrics(transaction) @@ -1015,7 +1064,7 @@ class EventService( '${escapeSql(ctx.transactionName)}', '${escapeSql(transactionOp)}', fromUnixTimestamp64Nano(${unixSecondsToNanos(startTs)}), - ${durationNanos(transaction.start_timestamp, transaction.timestamp)}, + ${durationNanos(transaction.startTimestamp, transaction.timestamp)}, ${sentryStatusToError(traceStatus)}, ${mapToSqlMap(ctx.baseMeta)}, ${doubleMapToSqlMap(rootMetrics)}, @@ -1036,14 +1085,14 @@ class EventService( fallbackTraceId: String, transaction: SentryTransaction ): String? { - val spanStart = span.start_timestamp ?: transaction.start_timestamp ?: return null + val spanStart = span.startTimestamp ?: transaction.startTimestamp ?: return null val spanEnd = span.timestamp ?: transaction.timestamp ?: spanStart - val spanId = span.span_id?.ifBlank { null } ?: UUID.randomUUID().toString().replace("-", "") - val spanTraceId = span.trace_id ?: fallbackTraceId + val spanId = span.spanId?.ifBlank { null } ?: UUID.randomUUID().toString().replace("-", "") + val spanTraceId = span.traceId ?: fallbackTraceId val (traceIdHigh, traceIdLow) = hexToULongPair(spanTraceId) val (spanIdHigh, spanIdLow) = hexToULongPair(spanId) - val parentHex = span.parent_span_id ?: "" + val parentHex = span.parentSpanId ?: "" val (parentIdHigh, parentIdLow) = hexToULongPair(parentHex) val spanMeta = extractSpanMeta(span, ctx.baseMeta) @@ -1079,7 +1128,7 @@ class EventService( val metrics = mutableMapOf() transaction.measurements?.let { measurements -> for ((key, value) in measurements) { - suspendRunCatching { + runCatching { val numericValue = value.jsonObject["value"]?.jsonPrimitive?.contentOrNull?.toDoubleOrNull() if (numericValue != null) metrics["measurement.$key"] = numericValue }.getOrElse { e -> @@ -1103,7 +1152,7 @@ class EventService( span.tags?.let { mergeNonReservedTags(meta, it) } span.data?.let { data -> for ((key, value) in data) { - suspendRunCatching { + runCatching { val str = value.jsonPrimitive.contentOrNull if (str != null) meta["data.$key"] = str }.getOrElse { e -> @@ -1118,7 +1167,7 @@ class EventService( val metrics = mutableMapOf() span.data?.let { data -> for ((key, value) in data) { - suspendRunCatching { + runCatching { val num = value.jsonPrimitive.contentOrNull?.toDoubleOrNull() if (num != null) metrics["data.$key"] = num }.getOrElse { e -> diff --git a/backend/src/main/kotlin/com/moneat/incident/services/IncidentIoProvider.kt b/backend/src/main/kotlin/com/moneat/incident/services/IncidentIoProvider.kt index 9188d34b8..bdf36c416 100644 --- a/backend/src/main/kotlin/com/moneat/incident/services/IncidentIoProvider.kt +++ b/backend/src/main/kotlin/com/moneat/incident/services/IncidentIoProvider.kt @@ -91,7 +91,7 @@ class IncidentIoProvider : IncidentProvider { val payload = AlertEventPayload( - deduplication_key = event.deduplicationKey, + deduplicationKey = event.deduplicationKey, status = when (event.status) { IncidentStatus.FIRING -> "firing" @@ -111,7 +111,7 @@ class IncidentIoProvider : IncidentProvider { if (response.status.value in 200..299) { val responseBody = response.body() - Result.success(responseBody.deduplication_key) + Result.success(responseBody.deduplicationKey) } else { val errorBody = response.bodyAsText() Result.failure(Exception("incident.io API error (${response.status}): $errorBody")) @@ -133,7 +133,7 @@ class IncidentIoProvider : IncidentProvider { val payload = AlertEventPayload( - deduplication_key = deduplicationKey, + deduplicationKey = deduplicationKey, status = "resolved", title = "Alert Resolved", description = "This alert has been automatically resolved by Moneat", @@ -149,7 +149,7 @@ class IncidentIoProvider : IncidentProvider { if (response.status.value in 200..299) { val responseBody = response.body() - Result.success(responseBody.deduplication_key) + Result.success(responseBody.deduplicationKey) } else { val errorBody = response.bodyAsText() Result.failure(Exception("incident.io API error (${response.status}): $errorBody")) @@ -170,7 +170,7 @@ class IncidentIoProvider : IncidentProvider { val testDedup = "moneat-test-${System.currentTimeMillis()}" val payload = AlertEventPayload( - deduplication_key = testDedup, + deduplicationKey = testDedup, status = "firing", title = "Moneat Test Alert", description = "This is a test alert from Moneat to verify the integration", @@ -200,7 +200,7 @@ class IncidentIoProvider : IncidentProvider { @Serializable private data class AlertEventPayload( - val deduplication_key: String, + @kotlinx.serialization.SerialName("deduplication_key") val deduplicationKey: String, val status: String, val title: String, val description: String, @@ -209,7 +209,7 @@ class IncidentIoProvider : IncidentProvider { @Serializable private data class AlertEventResponse( - val deduplication_key: String + @kotlinx.serialization.SerialName("deduplication_key") val deduplicationKey: String ) } diff --git a/backend/src/main/kotlin/com/moneat/monitor/models/MonitorModels.kt b/backend/src/main/kotlin/com/moneat/monitor/models/MonitorModels.kt index 630a8b8e1..da28327fc 100644 --- a/backend/src/main/kotlin/com/moneat/monitor/models/MonitorModels.kt +++ b/backend/src/main/kotlin/com/moneat/monitor/models/MonitorModels.kt @@ -61,62 +61,62 @@ data class HostResponse( val name: String, val hostname: String, val status: String, - val last_seen_at: Long?, + @SerialName("last_seen_at") val lastSeenAt: Long?, @SerialName("first_seen_at") val firstSeenAt: Long? = null, - val agent_version: String?, + @SerialName("agent_version") val agentVersion: String?, val os: String?, val arch: String?, val platform: String? = null, val processor: String? = null, @SerialName("cpu_cores") val cpuCores: Int? = null, @SerialName("memory_total_kb") val memoryTotalKb: Long? = null, - val created_at: Long, - val latest_metrics: LatestMetrics? + @SerialName("created_at") val createdAt: Long, + @SerialName("latest_metrics") val latestMetrics: LatestMetrics? ) @Serializable data class LatestMetrics( - val cpu_percent: Float, - val mem_total: Long, - val mem_used: Long, - val mem_percent: Float, - val disk_total: Long, - val disk_used: Long, - val disk_percent: Float, - val net_recv_bytes: Long, - val net_sent_bytes: Long, - val net_recv_mbps: Float?, - val net_sent_mbps: Float?, - val load_1: Float, - val temp_max: Float?, - val gpu_percent: Float?, - val battery_percent: Float? + @SerialName("cpu_percent") val cpuPercent: Float, + @SerialName("mem_total") val memTotal: Long, + @SerialName("mem_used") val memUsed: Long, + @SerialName("mem_percent") val memPercent: Float, + @SerialName("disk_total") val diskTotal: Long, + @SerialName("disk_used") val diskUsed: Long, + @SerialName("disk_percent") val diskPercent: Float, + @SerialName("net_recv_bytes") val netRecvBytes: Long, + @SerialName("net_sent_bytes") val netSentBytes: Long, + @SerialName("net_recv_mbps") val netRecvMbps: Float?, + @SerialName("net_sent_mbps") val netSentMbps: Float?, + @SerialName("load_1") val load1: Float, + @SerialName("temp_max") val tempMax: Float?, + @SerialName("gpu_percent") val gpuPercent: Float?, + @SerialName("battery_percent") val batteryPercent: Float? ) @Serializable data class HistoricalMetricsResponse( - val system_id: String, - val host_id: Int? = null, + @SerialName("system_id") val systemId: String, + @SerialName("host_id") val hostId: Int? = null, val from: Long, val to: Long, - val interval_seconds: Int, - val data_points: List + @SerialName("interval_seconds") val intervalSeconds: Int, + @SerialName("data_points") val dataPoints: List ) @Serializable data class MetricDataPoint( val timestamp: Long, - val cpu_percent: Float?, - val mem_percent: Float?, - val disk_percent: Float?, - val net_recv_bytes: Long?, - val net_sent_bytes: Long?, - val load_1: Float?, - val load_5: Float?, - val load_15: Float?, - val temp_max: Float?, - val gpu_percent: Float?, - val battery_percent: Float? + @SerialName("cpu_percent") val cpuPercent: Float?, + @SerialName("mem_percent") val memPercent: Float?, + @SerialName("disk_percent") val diskPercent: Float?, + @SerialName("net_recv_bytes") val netRecvBytes: Long?, + @SerialName("net_sent_bytes") val netSentBytes: Long?, + @SerialName("load_1") val load1: Float?, + @SerialName("load_5") val load5: Float?, + @SerialName("load_15") val load15: Float?, + @SerialName("temp_max") val tempMax: Float?, + @SerialName("gpu_percent") val gpuPercent: Float?, + @SerialName("battery_percent") val batteryPercent: Float? ) @Serializable @@ -152,31 +152,31 @@ data class ContainerStats( val id: String, val image: String, val status: String, - val cpu_percent: Float, - val mem_used: Long, - val mem_limit: Long, - val net_recv_bytes: Long, - val net_sent_bytes: Long, - val mem_percent: Float + @SerialName("cpu_percent") val cpuPercent: Float, + @SerialName("mem_used") val memUsed: Long, + @SerialName("mem_limit") val memLimit: Long, + @SerialName("net_recv_bytes") val netRecvBytes: Long, + @SerialName("net_sent_bytes") val netSentBytes: Long, + @SerialName("mem_percent") val memPercent: Float ) @Serializable data class ContainerMetricsResponse( - val container_name: String, + @SerialName("container_name") val containerName: String, val from: Long, val to: Long, - val interval_seconds: Int, - val data_points: List + @SerialName("interval_seconds") val intervalSeconds: Int, + @SerialName("data_points") val dataPoints: List ) @Serializable data class ContainerMetricDataPoint( val timestamp: Long, - val cpu_percent: Float?, - val mem_used: Long?, - val mem_limit: Long?, - val net_recv_bytes: Long?, - val net_sent_bytes: Long? + @SerialName("cpu_percent") val cpuPercent: Float?, + @SerialName("mem_used") val memUsed: Long?, + @SerialName("mem_limit") val memLimit: Long?, + @SerialName("net_recv_bytes") val netRecvBytes: Long?, + @SerialName("net_sent_bytes") val netSentBytes: Long? ) @Serializable diff --git a/backend/src/main/kotlin/com/moneat/monitor/routes/MonitorRoutes.kt b/backend/src/main/kotlin/com/moneat/monitor/routes/MonitorRoutes.kt index 15398fd11..05e863dcc 100644 --- a/backend/src/main/kotlin/com/moneat/monitor/routes/MonitorRoutes.kt +++ b/backend/src/main/kotlin/com/moneat/monitor/routes/MonitorRoutes.kt @@ -124,17 +124,17 @@ fun Route.monitorRoutes( name = host.displayName ?: host.hostname, hostname = host.hostname, status = host.status, - last_seen_at = host.lastSeenAt?.toEpochMilliseconds(), + lastSeenAt = host.lastSeenAt?.toEpochMilliseconds(), firstSeenAt = host.firstSeenAt.toEpochMilliseconds(), - agent_version = host.agentVersion, + agentVersion = host.agentVersion, os = host.os, arch = host.arch, platform = host.platform, processor = host.processor, cpuCores = host.cpuCores, memoryTotalKb = host.memoryTotalKb, - created_at = host.createdAt.toEpochMilliseconds(), - latest_metrics = latestMetricsByHost[host.id] + createdAt = host.createdAt.toEpochMilliseconds(), + latestMetrics = latestMetricsByHost[host.id] ) } @@ -186,17 +186,17 @@ fun Route.monitorRoutes( name = host.displayName ?: host.hostname, hostname = host.hostname, status = host.status, - last_seen_at = host.lastSeenAt?.toEpochMilliseconds(), + lastSeenAt = host.lastSeenAt?.toEpochMilliseconds(), firstSeenAt = host.firstSeenAt.toEpochMilliseconds(), - agent_version = host.agentVersion, + agentVersion = host.agentVersion, os = host.os, arch = host.arch, platform = host.platform, processor = host.processor, cpuCores = host.cpuCores, memoryTotalKb = host.memoryTotalKb, - created_at = host.createdAt.toEpochMilliseconds(), - latest_metrics = monitorService.getLatestMetrics(host.id) + createdAt = host.createdAt.toEpochMilliseconds(), + latestMetrics = monitorService.getLatestMetrics(host.id) ) ) } diff --git a/backend/src/main/kotlin/com/moneat/monitor/services/MonitorService.kt b/backend/src/main/kotlin/com/moneat/monitor/services/MonitorService.kt index 59fa9281b..0627938c1 100644 --- a/backend/src/main/kotlin/com/moneat/monitor/services/MonitorService.kt +++ b/backend/src/main/kotlin/com/moneat/monitor/services/MonitorService.kt @@ -221,21 +221,21 @@ class MonitorService( val effectiveMemUsed = if (memAvailable > 0) memTotal - memAvailable else memUsed return LatestMetrics( - cpu_percent = cpuPercent, - mem_total = memTotal, - mem_used = effectiveMemUsed, - mem_percent = if (memTotal > 0) (effectiveMemUsed.toFloat() / memTotal * 100) else 0f, - disk_total = diskTotal, - disk_used = diskUsed, - disk_percent = if (diskTotal > 0) (diskUsed.toFloat() / diskTotal * 100) else 0f, - net_recv_bytes = netRecvBytes, - net_sent_bytes = netSentBytes, - net_recv_mbps = null, - net_sent_mbps = null, - load_1 = load1, - temp_max = tempMax, - gpu_percent = gpuPercent, - battery_percent = batteryPercent + cpuPercent = cpuPercent, + memTotal = memTotal, + memUsed = effectiveMemUsed, + memPercent = if (memTotal > 0) (effectiveMemUsed.toFloat() / memTotal * 100) else 0f, + diskTotal = diskTotal, + diskUsed = diskUsed, + diskPercent = if (diskTotal > 0) (diskUsed.toFloat() / diskTotal * 100) else 0f, + netRecvBytes = netRecvBytes, + netSentBytes = netSentBytes, + netRecvMbps = null, + netSentMbps = null, + load1 = load1, + tempMax = tempMax, + gpuPercent = gpuPercent, + batteryPercent = batteryPercent ) }.getOrElse { e -> logger.warn(e) { "Failed to parse latest metrics response" } @@ -300,21 +300,21 @@ class MonitorService( val batteryPercent = arr.getOrNull(12)?.toString()?.toFloatOrNull() val effectiveMemUsed = if (memAvailable > 0) memTotal - memAvailable else memUsed result[rowHostId] = LatestMetrics( - cpu_percent = cpuPercent, - mem_total = memTotal, - mem_used = effectiveMemUsed, - mem_percent = if (memTotal > 0) (effectiveMemUsed.toFloat() / memTotal * 100) else 0f, - disk_total = diskTotal, - disk_used = diskUsed, - disk_percent = if (diskTotal > 0) (diskUsed.toFloat() / diskTotal * 100) else 0f, - net_recv_bytes = netRecvBytes, - net_sent_bytes = netSentBytes, - net_recv_mbps = null, - net_sent_mbps = null, - load_1 = load1, - temp_max = tempMax, - gpu_percent = gpuPercent, - battery_percent = batteryPercent + cpuPercent = cpuPercent, + memTotal = memTotal, + memUsed = effectiveMemUsed, + memPercent = if (memTotal > 0) (effectiveMemUsed.toFloat() / memTotal * 100) else 0f, + diskTotal = diskTotal, + diskUsed = diskUsed, + diskPercent = if (diskTotal > 0) (diskUsed.toFloat() / diskTotal * 100) else 0f, + netRecvBytes = netRecvBytes, + netSentBytes = netSentBytes, + netRecvMbps = null, + netSentMbps = null, + load1 = load1, + tempMax = tempMax, + gpuPercent = gpuPercent, + batteryPercent = batteryPercent ) } hostIds.associateWith { result[it] } @@ -338,22 +338,22 @@ class MonitorService( MONITOR_HISTORY_CACHE_TTL_SECONDS ) { val host = getHostById(hostId) ?: return@cached HistoricalMetricsResponse( - system_id = "", - host_id = hostId, + systemId = "", + hostId = hostId, from = fromTimestamp, to = toTimestamp, - interval_seconds = intervalSeconds ?: 3600, - data_points = emptyList() + intervalSeconds = intervalSeconds ?: 3600, + dataPoints = emptyList() ) val clampedWindow = clampRangeToRetention(hostId, fromTimestamp, toTimestamp) if (clampedWindow == null) { return@cached HistoricalMetricsResponse( - system_id = "", - host_id = hostId, + systemId = "", + hostId = hostId, from = fromTimestamp, to = toTimestamp, - interval_seconds = intervalSeconds ?: 3600, - data_points = emptyList() + intervalSeconds = intervalSeconds ?: 3600, + dataPoints = emptyList() ) } val (effectiveFrom, effectiveTo) = clampedWindow @@ -403,39 +403,39 @@ class MonitorService( val result = json.parseToJsonElement(body).jsonObject val data = result["data"]?.jsonArray ?: return@cached HistoricalMetricsResponse( - system_id = "", - host_id = hostId, + systemId = "", + hostId = hostId, from = effectiveFrom, to = effectiveTo, - interval_seconds = calculatedInterval, - data_points = emptyList() + intervalSeconds = calculatedInterval, + dataPoints = emptyList() ) data.map { row -> val arr = row.jsonArray MetricDataPoint( timestamp = arr[0].toString().replace("\"", "").toLong(), - cpu_percent = arr.getOrNull(1)?.toString()?.toFloatOrNull(), - mem_percent = arr.getOrNull(2)?.toString()?.toFloatOrNull(), - disk_percent = arr.getOrNull(3)?.toString()?.toFloatOrNull(), - net_recv_bytes = + cpuPercent = arr.getOrNull(1)?.toString()?.toFloatOrNull(), + memPercent = arr.getOrNull(2)?.toString()?.toFloatOrNull(), + diskPercent = arr.getOrNull(3)?.toString()?.toFloatOrNull(), + netRecvBytes = arr .getOrNull(4) ?.toString() ?.replace("\"", "") ?.toLongOrNull(), - net_sent_bytes = + netSentBytes = arr .getOrNull(5) ?.toString() ?.replace("\"", "") ?.toLongOrNull(), - load_1 = arr.getOrNull(6)?.toString()?.toFloatOrNull(), - load_5 = arr.getOrNull(7)?.toString()?.toFloatOrNull(), - load_15 = arr.getOrNull(8)?.toString()?.toFloatOrNull(), - temp_max = arr.getOrNull(9)?.toString()?.toFloatOrNull(), - gpu_percent = arr.getOrNull(10)?.toString()?.toFloatOrNull(), - battery_percent = arr.getOrNull(11)?.toString()?.toFloatOrNull() + load1 = arr.getOrNull(6)?.toString()?.toFloatOrNull(), + load5 = arr.getOrNull(7)?.toString()?.toFloatOrNull(), + load15 = arr.getOrNull(8)?.toString()?.toFloatOrNull(), + tempMax = arr.getOrNull(9)?.toString()?.toFloatOrNull(), + gpuPercent = arr.getOrNull(10)?.toString()?.toFloatOrNull(), + batteryPercent = arr.getOrNull(11)?.toString()?.toFloatOrNull() ) } }.getOrElse { e -> @@ -444,12 +444,12 @@ class MonitorService( } HistoricalMetricsResponse( - system_id = "", - host_id = hostId, + systemId = "", + hostId = hostId, from = effectiveFrom, to = effectiveTo, - interval_seconds = calculatedInterval, - data_points = dataPoints + intervalSeconds = calculatedInterval, + dataPoints = dataPoints ) } @@ -497,12 +497,12 @@ class MonitorService( id = arr[1].toString().replace("\"", ""), image = arr[2].toString().replace("\"", ""), status = arr[3].toString().replace("\"", ""), - cpu_percent = arr[4].toString().toFloatOrNull() ?: 0f, - mem_used = memUsed, - mem_limit = memLimit, - net_recv_bytes = netRecvBytes, - net_sent_bytes = netSentBytes, - mem_percent = if (memLimit > 0) (memUsed.toFloat() / memLimit * 100) else 0f + cpuPercent = arr[4].toString().toFloatOrNull() ?: 0f, + memUsed = memUsed, + memLimit = memLimit, + netRecvBytes = netRecvBytes, + netSentBytes = netSentBytes, + memPercent = if (memLimit > 0) (memUsed.toFloat() / memLimit * 100) else 0f ) } }.getOrElse { e -> @@ -530,12 +530,12 @@ class MonitorService( id = c.id, image = c.image, status = c.status, - cpuPercent = c.cpu_percent, - memUsed = c.mem_used, - memLimit = c.mem_limit, - netRecvBytes = c.net_recv_bytes, - netSentBytes = c.net_sent_bytes, - memPercent = c.mem_percent + cpuPercent = c.cpuPercent, + memUsed = c.memUsed, + memLimit = c.memLimit, + netRecvBytes = c.netRecvBytes, + netSentBytes = c.netSentBytes, + memPercent = c.memPercent ) ) } @@ -636,20 +636,20 @@ class MonitorService( intervalSeconds: Int? ): ContainerMetricsResponse { val host = getHostById(hostId) ?: return ContainerMetricsResponse( - container_name = containerName, + containerName = containerName, from = fromTimestamp, to = toTimestamp, - interval_seconds = intervalSeconds ?: 3600, - data_points = emptyList() + intervalSeconds = intervalSeconds ?: 3600, + dataPoints = emptyList() ) val clampedWindow = clampRangeToRetention(hostId, fromTimestamp, toTimestamp) if (clampedWindow == null) { return ContainerMetricsResponse( - container_name = containerName, + containerName = containerName, from = fromTimestamp, to = toTimestamp, - interval_seconds = intervalSeconds ?: 3600, - data_points = emptyList() + intervalSeconds = intervalSeconds ?: 3600, + dataPoints = emptyList() ) } val (effectiveFrom, effectiveTo) = clampedWindow @@ -692,37 +692,37 @@ class MonitorService( val result = json.parseToJsonElement(body).jsonObject val data = result["data"]?.jsonArray ?: return ContainerMetricsResponse( - container_name = containerName, + containerName = containerName, from = effectiveFrom, to = effectiveTo, - interval_seconds = calculatedInterval, - data_points = emptyList() + intervalSeconds = calculatedInterval, + dataPoints = emptyList() ) data.map { row -> val arr = row.jsonArray ContainerMetricDataPoint( timestamp = arr[0].toString().replace("\"", "").toLong(), - cpu_percent = arr.getOrNull(1)?.toString()?.toFloatOrNull(), - mem_used = + cpuPercent = arr.getOrNull(1)?.toString()?.toFloatOrNull(), + memUsed = arr .getOrNull(2) ?.toString() ?.replace("\"", "") ?.toLongOrNull(), - mem_limit = + memLimit = arr .getOrNull(3) ?.toString() ?.replace("\"", "") ?.toLongOrNull(), - net_recv_bytes = + netRecvBytes = arr .getOrNull(4) ?.toString() ?.replace("\"", "") ?.toLongOrNull(), - net_sent_bytes = + netSentBytes = arr .getOrNull(5) ?.toString() @@ -736,11 +736,11 @@ class MonitorService( } return ContainerMetricsResponse( - container_name = containerName, + containerName = containerName, from = effectiveFrom, to = effectiveTo, - interval_seconds = calculatedInterval, - data_points = dataPoints + intervalSeconds = calculatedInterval, + dataPoints = dataPoints ) } diff --git a/backend/src/main/kotlin/com/moneat/notifications/services/DiscordService.kt b/backend/src/main/kotlin/com/moneat/notifications/services/DiscordService.kt index 1904aa996..a526a50df 100644 --- a/backend/src/main/kotlin/com/moneat/notifications/services/DiscordService.kt +++ b/backend/src/main/kotlin/com/moneat/notifications/services/DiscordService.kt @@ -33,6 +33,7 @@ import io.ktor.http.HttpHeaders import io.ktor.http.HttpStatusCode import io.ktor.http.Parameters import io.ktor.http.contentType +import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable import kotlinx.serialization.json.Json import org.jetbrains.exposed.v1.core.and @@ -94,8 +95,8 @@ class DiscordService( @Serializable data class DiscordOAuthResponse( - val access_token: String? = null, - val token_type: String? = null, + @SerialName("access_token") val accessToken: String? = null, + @SerialName("token_type") val tokenType: String? = null, val scope: String? = null, val guild: DiscordGuild? = null, val error: String? = null diff --git a/backend/src/main/kotlin/com/moneat/notifications/services/SlackService.kt b/backend/src/main/kotlin/com/moneat/notifications/services/SlackService.kt index d1bbd75f7..1c7e0444e 100644 --- a/backend/src/main/kotlin/com/moneat/notifications/services/SlackService.kt +++ b/backend/src/main/kotlin/com/moneat/notifications/services/SlackService.kt @@ -34,6 +34,7 @@ import io.ktor.client.statement.bodyAsText import io.ktor.http.ContentType import io.ktor.http.HttpStatusCode import io.ktor.http.contentType +import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable import kotlinx.serialization.json.Json import org.jetbrains.exposed.v1.core.and @@ -78,7 +79,7 @@ class SlackService { val type: String, val text: SlackText? = null, val url: String? = null, - val action_id: String? = null + @SerialName("action_id") val actionId: String? = null ) @Serializable @@ -105,11 +106,11 @@ class SlackService { @Serializable data class SlackOAuthResponse( val ok: Boolean, - val access_token: String? = null, - val token_type: String? = null, + @SerialName("access_token") val accessToken: String? = null, + @SerialName("token_type") val tokenType: String? = null, val scope: String? = null, - val bot_user_id: String? = null, - val app_id: String? = null, + @SerialName("bot_user_id") val botUserId: String? = null, + @SerialName("app_id") val appId: String? = null, val team: SlackTeam? = null, val error: String? = null ) @@ -826,7 +827,7 @@ class SlackService { data class SlackChannel( val id: String, val name: String, - val is_private: Boolean? = null + @SerialName("is_private") val isPrivate: Boolean? = null ) suspend fun listChannels(accessToken: String): List { @@ -959,7 +960,7 @@ class SlackService { SlackElement( type = "button", text = SlackText(type = "plain_text", text = "Acknowledge", emoji = false), - action_id = "incident_acknowledge_$incidentId" + actionId = "incident_acknowledge_$incidentId" ), SlackElement( type = "button", @@ -968,7 +969,7 @@ class SlackService { "FRONTEND_URL", "https://moneat.io" )}/on-call/incidents/$incidentId", - action_id = "incident_view_$incidentId" + actionId = "incident_view_$incidentId" ) ) ) diff --git a/backend/src/main/kotlin/com/moneat/org/routes/IntegrationRoutes.kt b/backend/src/main/kotlin/com/moneat/org/routes/IntegrationRoutes.kt index 75f59171c..90455f5d9 100644 --- a/backend/src/main/kotlin/com/moneat/org/routes/IntegrationRoutes.kt +++ b/backend/src/main/kotlin/com/moneat/org/routes/IntegrationRoutes.kt @@ -794,7 +794,7 @@ fun Route.integrationCallbackRoutes() { val oauthResponse = slackService.exchangeOAuthCode(code, clientId, clientSecret, redirectUri) - if (oauthResponse.ok && oauthResponse.access_token != null) { + if (oauthResponse.ok && oauthResponse.accessToken != null) { val now = Clock.System.now() transaction { @@ -812,8 +812,8 @@ fun Route.integrationCallbackRoutes() { (OrganizationIntegrations.organization_id eq organizationId) and (OrganizationIntegrations.integration_type eq "slack") }) { - it[access_token] = oauthResponse.access_token - it[bot_user_id] = oauthResponse.bot_user_id + it[access_token] = oauthResponse.accessToken + it[bot_user_id] = oauthResponse.botUserId it[team_id] = oauthResponse.team?.id it[team_name] = oauthResponse.team?.name it[enabled] = true @@ -824,8 +824,8 @@ fun Route.integrationCallbackRoutes() { OrganizationIntegrations.insert { it[organization_id] = organizationId it[integration_type] = "slack" - it[access_token] = oauthResponse.access_token - it[bot_user_id] = oauthResponse.bot_user_id + it[access_token] = oauthResponse.accessToken + it[bot_user_id] = oauthResponse.botUserId it[team_id] = oauthResponse.team?.id it[team_name] = oauthResponse.team?.name it[enabled] = true @@ -905,7 +905,7 @@ fun Route.integrationCallbackRoutes() { // Exchange code for access token val oauthResponse = discordService.exchangeOAuthCode(code, clientId, clientSecret, redirectUri) - if (oauthResponse.access_token != null && oauthResponse.guild != null) { + if (oauthResponse.accessToken != null && oauthResponse.guild != null) { val now = Clock.System.now() transaction { @@ -922,7 +922,7 @@ fun Route.integrationCallbackRoutes() { (OrganizationIntegrations.organization_id eq organizationId) and (OrganizationIntegrations.integration_type eq "discord") }) { - it[access_token] = oauthResponse.access_token + it[access_token] = oauthResponse.accessToken it[team_id] = oauthResponse.guild.id it[team_name] = oauthResponse.guild.name it[enabled] = true @@ -932,7 +932,7 @@ fun Route.integrationCallbackRoutes() { OrganizationIntegrations.insert { it[organization_id] = organizationId it[integration_type] = "discord" - it[access_token] = oauthResponse.access_token + it[access_token] = oauthResponse.accessToken it[team_id] = oauthResponse.guild.id it[team_name] = oauthResponse.guild.name it[enabled] = true diff --git a/backend/src/main/kotlin/com/moneat/shared/services/SdkVersionService.kt b/backend/src/main/kotlin/com/moneat/shared/services/SdkVersionService.kt index d69b755c7..bf7eafbf9 100644 --- a/backend/src/main/kotlin/com/moneat/shared/services/SdkVersionService.kt +++ b/backend/src/main/kotlin/com/moneat/shared/services/SdkVersionService.kt @@ -31,6 +31,7 @@ import io.ktor.http.HttpHeaders import io.ktor.http.HttpStatusCode import kotlinx.coroutines.async import kotlinx.coroutines.coroutineScope +import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable import kotlinx.serialization.builtins.ListSerializer import kotlinx.serialization.json.Json @@ -54,7 +55,7 @@ private data class VersionTarget( @Serializable private data class GitHubLatestReleaseResponse( - val tag_name: String? = null, + @SerialName("tag_name") val tagName: String? = null, val prerelease: Boolean = false, val draft: Boolean = false, ) @@ -214,7 +215,7 @@ object SdkVersionService { return null } - return normalizeVersionTag(release.tag_name.orEmpty()) + return normalizeVersionTag(release.tagName.orEmpty()) } private suspend fun fetchFromTags(repository: String): String? { diff --git a/backend/src/main/kotlin/com/moneat/summary/services/SummaryService.kt b/backend/src/main/kotlin/com/moneat/summary/services/SummaryService.kt index fb4f07a9a..27b1f1e49 100644 --- a/backend/src/main/kotlin/com/moneat/summary/services/SummaryService.kt +++ b/backend/src/main/kotlin/com/moneat/summary/services/SummaryService.kt @@ -307,11 +307,11 @@ class SummaryService( } val avgCpu = hostMetrics - .map { it.cpu_percent.toDouble() } + .map { it.cpuPercent.toDouble() } .takeIf { it.isNotEmpty() }?.average() ?: 0.0 val avgMem = hostMetrics - .map { it.mem_percent.toDouble() } + .map { it.memPercent.toDouble() } .takeIf { it.isNotEmpty() }?.average() ?: 0.0 WeeklyReportResponse( @@ -377,10 +377,10 @@ class SummaryService( hostMetrics = HostMetricsWindow( systemId = host.id.toString(), systemName = host.displayName ?: host.hostname, - avgCpu = metrics.cpu_percent.toDouble(), - maxCpu = metrics.cpu_percent.toDouble(), - avgMemory = metrics.mem_percent.toDouble(), - maxMemory = metrics.mem_percent.toDouble(), + avgCpu = metrics.cpuPercent.toDouble(), + maxCpu = metrics.cpuPercent.toDouble(), + avgMemory = metrics.memPercent.toDouble(), + maxMemory = metrics.memPercent.toDouble(), windowStart = isoFormatter.format(windowStart), windowEnd = isoFormatter.format(now) ) @@ -409,10 +409,10 @@ class SummaryService( hostMetrics = HostMetricsWindow( systemId = host.id.toString(), systemName = host.displayName ?: host.hostname, - avgCpu = metrics.cpu_percent.toDouble(), - maxCpu = metrics.cpu_percent.toDouble(), - avgMemory = metrics.mem_percent.toDouble(), - maxMemory = metrics.mem_percent.toDouble(), + avgCpu = metrics.cpuPercent.toDouble(), + maxCpu = metrics.cpuPercent.toDouble(), + avgMemory = metrics.memPercent.toDouble(), + maxMemory = metrics.memPercent.toDouble(), windowStart = isoFormatter.format(windowStart), windowEnd = isoFormatter.format(now) ) diff --git a/backend/src/test/kotlin/com/moneat/ai/AiChatServiceTest.kt b/backend/src/test/kotlin/com/moneat/ai/AiChatServiceTest.kt index 2f7bcb214..8717171ad 100644 --- a/backend/src/test/kotlin/com/moneat/ai/AiChatServiceTest.kt +++ b/backend/src/test/kotlin/com/moneat/ai/AiChatServiceTest.kt @@ -64,10 +64,10 @@ class AiChatServiceTest { val parsed = service.parseAiResponse("""{"message":"hello","context_needed":["logs"]}""") assertEquals("hello", parsed.message) - assertEquals(listOf("logs"), parsed.context_needed) + assertEquals(listOf("logs"), parsed.contextNeeded) val fallback = service.parseAiResponse("not-json") assertEquals("not-json", fallback.message) - assertTrue(fallback.context_needed.isEmpty()) + assertTrue(fallback.contextNeeded.isEmpty()) } } diff --git a/backend/src/test/kotlin/com/moneat/models/SentryTimestampParsingTest.kt b/backend/src/test/kotlin/com/moneat/models/SentryTimestampParsingTest.kt index 59451466d..565a3330c 100644 --- a/backend/src/test/kotlin/com/moneat/models/SentryTimestampParsingTest.kt +++ b/backend/src/test/kotlin/com/moneat/models/SentryTimestampParsingTest.kt @@ -51,12 +51,12 @@ class SentryTimestampParsingTest { val transaction = json.decodeFromString(payload) - val startTs = transaction.start_timestamp + val startTs = transaction.startTimestamp val endTs = transaction.timestamp assertNotNull(startTs) assertNotNull(endTs) assertTrue(endTs >= startTs) - assertNotNull(transaction.spans?.firstOrNull()?.start_timestamp) + assertNotNull(transaction.spans?.firstOrNull()?.startTimestamp) assertNotNull(transaction.spans?.firstOrNull()?.timestamp) } @@ -75,7 +75,7 @@ class SentryTimestampParsingTest { val replayEvent = json.decodeFromString(payload) val replayTs = replayEvent.timestamp - val replayStartTs = replayEvent.replay_start_timestamp + val replayStartTs = replayEvent.replayStartTimestamp assertNotNull(replayTs) assertNotNull(replayStartTs) assertTrue(replayTs >= replayStartTs) diff --git a/backend/src/test/kotlin/com/moneat/routes/MonitorRoutesMockTest.kt b/backend/src/test/kotlin/com/moneat/routes/MonitorRoutesMockTest.kt index f8641c3a4..4a45e13b9 100644 --- a/backend/src/test/kotlin/com/moneat/routes/MonitorRoutesMockTest.kt +++ b/backend/src/test/kotlin/com/moneat/routes/MonitorRoutesMockTest.kt @@ -285,11 +285,11 @@ class MonitorRoutesMockTest { seedMembership(userId, orgId) val system = makeHostData(orgId) val metricsResponse = HistoricalMetricsResponse( - system_id = system.id.toString(), + systemId = system.id.toString(), from = 1000L, to = 2000L, - interval_seconds = 60, - data_points = emptyList() + intervalSeconds = 60, + dataPoints = emptyList() ) every { mockMonitorService.getHostById(system.id) } returns system @@ -326,12 +326,12 @@ class MonitorRoutesMockTest { id = "abc123", image = "nginx:latest", status = "running", - cpu_percent = 1.5f, - mem_used = 100L, - mem_limit = 512L, - net_recv_bytes = 0L, - net_sent_bytes = 0L, - mem_percent = 0.2f + cpuPercent = 1.5f, + memUsed = 100L, + memLimit = 512L, + netRecvBytes = 0L, + netSentBytes = 0L, + memPercent = 0.2f ) every { mockMonitorService.getHostById(system.id) } returns system @@ -700,11 +700,11 @@ class MonitorRoutesMockTest { seedMembership(userId, orgId) val system = makeHostData(orgId) val containerMetrics = ContainerMetricsResponse( - container_name = "my-container", + containerName = "my-container", from = 1000L, to = 2000L, - interval_seconds = 60, - data_points = emptyList() + intervalSeconds = 60, + dataPoints = emptyList() ) every { mockMonitorService.getHostById(system.id) } returns system diff --git a/backend/src/test/kotlin/com/moneat/services/DiscordServiceBuildersTest.kt b/backend/src/test/kotlin/com/moneat/services/DiscordServiceBuildersTest.kt index 90d5b9754..b31cb50c2 100644 --- a/backend/src/test/kotlin/com/moneat/services/DiscordServiceBuildersTest.kt +++ b/backend/src/test/kotlin/com/moneat/services/DiscordServiceBuildersTest.kt @@ -647,7 +647,7 @@ class DiscordServiceBuildersTest { @Test fun `DiscordOAuthResponse with error`() { val resp = DiscordService.DiscordOAuthResponse(error = "invalid_grant") - assertNull(resp.access_token) + assertNull(resp.accessToken) assertNull(resp.guild) assertTrue(resp.error == "invalid_grant") } diff --git a/backend/src/test/kotlin/com/moneat/services/EventServiceCoverageTest.kt b/backend/src/test/kotlin/com/moneat/services/EventServiceCoverageTest.kt index 612048fce..e26312790 100644 --- a/backend/src/test/kotlin/com/moneat/services/EventServiceCoverageTest.kt +++ b/backend/src/test/kotlin/com/moneat/services/EventServiceCoverageTest.kt @@ -146,7 +146,7 @@ class EventServiceCoverageTest { fun `processEnvelope routes event item to storeEvent`() = runBlocking { val eventJson = Json.encodeToString( SentryEvent( - event_id = "evt-1", + eventId = "evt-1", level = "error", message = "Test error", exception = ExceptionInfo( @@ -169,9 +169,9 @@ class EventServiceCoverageTest { fun `processEnvelope routes transaction item to storeTransaction`() = runBlocking { val txnJson = Json.encodeToString( SentryTransaction( - event_id = "txn-1", + eventId = "txn-1", transaction = "GET /api/users", - start_timestamp = 1700000000.0, + startTimestamp = 1700000000.0, timestamp = 1700000001.0, platform = "jvm", contexts = buildJsonObject { @@ -199,7 +199,7 @@ class EventServiceCoverageTest { fun `processEnvelope routes feedback item to storeFeedback`() = runBlocking { val fbJson = Json.encodeToString( SentryFeedback( - event_id = "fb-1", + eventId = "fb-1", timestamp = "2024-01-15T10:30:45Z", contexts = buildJsonObject { put( @@ -235,13 +235,13 @@ class EventServiceCoverageTest { fun `processEnvelope routes replay_event and replay_recording`() = runBlocking { val replayEventJson = Json.encodeToString( SentryReplayEvent( - replay_id = "replay-1", - segment_id = 0, + replayId = "replay-1", + segmentId = 0, timestamp = 1700000000.0, - replay_start_timestamp = 1699999990.0, + replayStartTimestamp = 1699999990.0, urls = listOf("https://example.com"), - error_ids = listOf("err-1"), - trace_ids = listOf("trace-1"), + errorIds = listOf("err-1"), + traceIds = listOf("trace-1"), platform = "javascript", environment = "production", user = UserInfo(id = "u1"), @@ -339,7 +339,7 @@ class EventServiceCoverageTest { fun `processEnvelope with multiple items processes all`() = runBlocking { val eventJson = Json.encodeToString( SentryEvent( - event_id = "evt-multi", + eventId = "evt-multi", level = "error", message = "Multi test", exception = ExceptionInfo( @@ -349,9 +349,9 @@ class EventServiceCoverageTest { ) val txnJson = Json.encodeToString( SentryTransaction( - event_id = "txn-multi", + eventId = "txn-multi", transaction = "test", - start_timestamp = 1700000000.0, + startTimestamp = 1700000000.0, timestamp = 1700000001.0, contexts = buildJsonObject { put( @@ -386,9 +386,9 @@ class EventServiceCoverageTest { fun `storeTransaction inserts spans from transaction`() = runBlocking { val txnJson = Json.encodeToString( SentryTransaction( - event_id = "txn-spans", + eventId = "txn-spans", transaction = "GET /items", - start_timestamp = 1700000000.0, + startTimestamp = 1700000000.0, timestamp = 1700000002.0, platform = "python", environment = "staging", @@ -405,22 +405,22 @@ class EventServiceCoverageTest { }, spans = listOf( SentrySpan( - span_id = "span1", - parent_span_id = "root", - trace_id = "trace-abc", + spanId = "span1", + parentSpanId = "root", + traceId = "trace-abc", op = "db.query", description = "SELECT * FROM items", - start_timestamp = 1700000000.5, + startTimestamp = 1700000000.5, timestamp = 1700000001.0, status = "ok", tags = mapOf("db.system" to "postgresql") ), SentrySpan( - span_id = "span2", - trace_id = "trace-abc", + spanId = "span2", + traceId = "trace-abc", op = "http.client", description = "GET /external", - start_timestamp = 1700000001.0, + startTimestamp = 1700000001.0, timestamp = 1700000001.5, status = "ok" ) @@ -462,9 +462,9 @@ class EventServiceCoverageTest { val txnJson = Json.encodeToString( SentryTransaction( - event_id = "txn-ai", + eventId = "txn-ai", transaction = "chat", - start_timestamp = 1700000000.0, + startTimestamp = 1700000000.0, timestamp = 1700000005.0, contexts = buildJsonObject { put( @@ -477,11 +477,11 @@ class EventServiceCoverageTest { }, spans = listOf( SentrySpan( - span_id = "ai-span-1", - trace_id = "trace-ai", + spanId = "ai-span-1", + traceId = "trace-ai", op = "ai.chat_completion", description = "OpenAI Chat", - start_timestamp = 1700000001.0, + startTimestamp = 1700000001.0, timestamp = 1700000003.0, status = "ok", data = buildJsonObject { @@ -493,11 +493,11 @@ class EventServiceCoverageTest { } ), SentrySpan( - span_id = "ai-span-2", - trace_id = "trace-ai", + spanId = "ai-span-2", + traceId = "trace-ai", op = "ai.embedding", description = "Embed query", - start_timestamp = 1700000003.0, + startTimestamp = 1700000003.0, timestamp = 1700000004.0, status = "ok", data = buildJsonObject { @@ -533,9 +533,9 @@ class EventServiceCoverageTest { val txnJson = Json.encodeToString( SentryTransaction( - event_id = "txn-err", + eventId = "txn-err", transaction = "POST /fail", - start_timestamp = 1700000000.0, + startTimestamp = 1700000000.0, timestamp = 1700000001.0, contexts = buildJsonObject { put( @@ -563,9 +563,9 @@ class EventServiceCoverageTest { fun `storeTransaction upserts release when present`() = runBlocking { val txnJson = Json.encodeToString( SentryTransaction( - event_id = "txn-rel", + eventId = "txn-rel", transaction = "test", - start_timestamp = 1700000000.0, + startTimestamp = 1700000000.0, timestamp = 1700000001.0, release = "v3.0.0", contexts = buildJsonObject { @@ -599,7 +599,7 @@ class EventServiceCoverageTest { val eventJson = Json.encodeToString( SentryEvent( - event_id = "crash-1", + eventId = "crash-1", exception = ExceptionInfo( values = listOf( ExceptionValue( @@ -631,7 +631,7 @@ class EventServiceCoverageTest { val eventJson = Json.encodeToString( SentryEvent( - event_id = "handled-1", + eventId = "handled-1", level = "warning", exception = ExceptionInfo( values = listOf( @@ -663,7 +663,7 @@ class EventServiceCoverageTest { val eventJson = Json.encodeToString( SentryEvent( - event_id = "fp-1", + eventId = "fp-1", exception = ExceptionInfo( values = listOf( ExceptionValue( @@ -675,13 +675,13 @@ class EventServiceCoverageTest { filename = "lib.py", function = "validate", lineno = 10, - in_app = false + inApp = false ), StackFrame( filename = "app.py", function = "process", lineno = 42, - in_app = true + inApp = true ) ) ) @@ -711,7 +711,7 @@ class EventServiceCoverageTest { val eventJson = Json.encodeToString( SentryEvent( - event_id = "custom-fp", + eventId = "custom-fp", fingerprint = listOf("custom", "group"), exception = ExceptionInfo( values = listOf(ExceptionValue(type = "Error", value = "test")) @@ -735,7 +735,7 @@ class EventServiceCoverageTest { val eventJson = Json.encodeToString( SentryEvent( - event_id = "msg-only", + eventId = "msg-only", message = "Something went wrong", level = "error" ) @@ -757,19 +757,19 @@ class EventServiceCoverageTest { val eventJson = Json.encodeToString( SentryEvent( - event_id = "full-event", + eventId = "full-event", timestamp = 1700000000.0, level = "info", platform = "python", environment = "staging", release = "2.5.0", dist = "abc123", - server_name = "web-03", + serverName = "web-03", user = UserInfo( id = "uid-1", email = "user@test.com", username = "testuser", - ip_address = "10.0.0.1" + ipAddress = "10.0.0.1" ), tags = mapOf("service" to "api", "region" to "us-east"), sdk = SdkInfo(name = "sentry-python", version = "1.5.0"), @@ -812,7 +812,7 @@ class EventServiceCoverageTest { @Test fun `storeFeedback with projectId 0 is rejected`() = runBlocking { val fbJson = Json.encodeToString( - SentryFeedback(event_id = "fb-bad") + SentryFeedback(eventId = "fb-bad") ) eventService.processEnvelope( @@ -833,7 +833,7 @@ class EventServiceCoverageTest { val fbJson = Json.encodeToString( SentryFeedback( - event_id = "fb-ts", + eventId = "fb-ts", timestamp = "2024-01-15T10:30:45Z", contexts = buildJsonObject { put( @@ -866,7 +866,7 @@ class EventServiceCoverageTest { val fbJson = Json.encodeToString( SentryFeedback( - event_id = "fb-bad-ts", + eventId = "fb-bad-ts", timestamp = "not-a-date", contexts = buildJsonObject { put( @@ -896,7 +896,7 @@ class EventServiceCoverageTest { @Test fun `storeReplayEvent with projectId 0 is rejected`() = runBlocking { val replayJson = Json.encodeToString( - SentryReplayEvent(replay_id = "replay-bad") + SentryReplayEvent(replayId = "replay-bad") ) eventService.processEnvelope( @@ -917,10 +917,10 @@ class EventServiceCoverageTest { val replayJson = Json.encodeToString( SentryReplayEvent( - replay_id = "replay-ctx", - segment_id = 3, + replayId = "replay-ctx", + segmentId = 3, timestamp = 1700000000.0, - replay_start_timestamp = 1699999990.0, + replayStartTimestamp = 1699999990.0, urls = listOf("https://a.com", "https://b.com"), contexts = buildJsonObject { put( @@ -983,7 +983,7 @@ class EventServiceCoverageTest { val body = Json.encodeToString( SentryEvent( - event_id = "store-1", + eventId = "store-1", level = "error", message = "Direct store", exception = ExceptionInfo( @@ -1029,9 +1029,9 @@ class EventServiceCoverageTest { val txnJson = Json.encodeToString( SentryTransaction( - event_id = "txn-fail", + eventId = "txn-fail", transaction = "test", - start_timestamp = 1700000000.0, + startTimestamp = 1700000000.0, timestamp = 1700000001.0, contexts = buildJsonObject { put( @@ -1065,7 +1065,7 @@ class EventServiceCoverageTest { val eventJson = Json.encodeToString( SentryEvent( - event_id = "evt-fail", + eventId = "evt-fail", exception = ExceptionInfo( values = listOf(ExceptionValue(type = "Error", value = "fail")) ) @@ -1092,61 +1092,61 @@ class EventServiceCoverageTest { val aiSpans = listOf( SentrySpan( - span_id = "s1", + spanId = "s1", op = "ai.chat_completion", description = "Chat", - start_timestamp = 1700000001.0, + startTimestamp = 1700000001.0, timestamp = 1700000002.0 ), SentrySpan( - span_id = "s2", + spanId = "s2", op = "ai.embedding", description = "Embed", - start_timestamp = 1700000002.0, + startTimestamp = 1700000002.0, timestamp = 1700000003.0 ), SentrySpan( - span_id = "s3", + spanId = "s3", op = "ai.tool_call", description = "Tool", - start_timestamp = 1700000003.0, + startTimestamp = 1700000003.0, timestamp = 1700000004.0 ), SentrySpan( - span_id = "s4", + spanId = "s4", op = "ai.agent", description = "Agent", - start_timestamp = 1700000004.0, + startTimestamp = 1700000004.0, timestamp = 1700000005.0 ), SentrySpan( - span_id = "s5", + spanId = "s5", op = "ai.chain", description = "Chain", - start_timestamp = 1700000005.0, + startTimestamp = 1700000005.0, timestamp = 1700000006.0 ), SentrySpan( - span_id = "s6", + spanId = "s6", op = "ai.retriever", description = "Retriever", - start_timestamp = 1700000006.0, + startTimestamp = 1700000006.0, timestamp = 1700000007.0 ), SentrySpan( - span_id = "s7", + spanId = "s7", op = "ai.run", description = "Generic", - start_timestamp = 1700000007.0, + startTimestamp = 1700000007.0, timestamp = 1700000008.0 ), ) val txnJson = Json.encodeToString( SentryTransaction( - event_id = "txn-ai-types", + eventId = "txn-ai-types", transaction = "ai-test", - start_timestamp = 1700000000.0, + startTimestamp = 1700000000.0, timestamp = 1700000010.0, contexts = buildJsonObject { put( diff --git a/backend/src/test/kotlin/com/moneat/services/EventServiceTest.kt b/backend/src/test/kotlin/com/moneat/services/EventServiceTest.kt index 86bd0525d..17e554915 100644 --- a/backend/src/test/kotlin/com/moneat/services/EventServiceTest.kt +++ b/backend/src/test/kotlin/com/moneat/services/EventServiceTest.kt @@ -338,7 +338,7 @@ class EventServiceTest { platform = "javascript" ) - assertNotNull(event.event_id, "Event ID should be present") + assertNotNull(event.eventId, "Event ID should be present") assertNotNull(event.exception, "Exception should be present") assertEquals("error", event.level, "Level should be error") assertEquals("javascript", event.platform, "Platform should be set") @@ -365,7 +365,7 @@ class EventServiceTest { id = "user-123", email = "test@example.com", username = "testuser", - ip_address = TestIpConstants.IP_1 + ipAddress = TestIpConstants.IP_1 ) val tags = @@ -486,7 +486,7 @@ class EventServiceTest { id = userId, email = userEmail, username = username, - ip_address = ipAddress + ipAddress = ipAddress ) val event = createSentryEvent(user = userInfo) @@ -494,7 +494,7 @@ class EventServiceTest { assertEquals(userId, event.user?.id, "User ID should be extracted") assertEquals(userEmail, event.user?.email, "User email should be extracted") assertEquals(username, event.user?.username, "Username should be extracted") - assertEquals(ipAddress, event.user?.ip_address, "IP address should be extracted") + assertEquals(ipAddress, event.user?.ipAddress, "IP address should be extracted") } @Test @@ -694,7 +694,7 @@ class EventServiceTest { .stacktrace ?.frames ?.get(0) - ?.in_app + ?.inApp ) assertEquals( false, @@ -702,7 +702,7 @@ class EventServiceTest { .stacktrace ?.frames ?.get(2) - ?.in_app + ?.inApp ) } @@ -744,7 +744,7 @@ class EventServiceTest { } return SentryEvent( - event_id = eventId ?: UUID.randomUUID().toString(), + eventId = eventId ?: UUID.randomUUID().toString(), timestamp = timestamp, level = level, message = message, @@ -772,8 +772,8 @@ class EventServiceTest { filename = filename, function = function, lineno = lineno, - in_app = inApp, - abs_path = "/app/$filename" + inApp = inApp, + absPath = "/app/$filename" ) } } diff --git a/backend/src/test/kotlin/com/moneat/services/MonitorServiceExtendedTest.kt b/backend/src/test/kotlin/com/moneat/services/MonitorServiceExtendedTest.kt index d430ceb14..6d3d04af9 100644 --- a/backend/src/test/kotlin/com/moneat/services/MonitorServiceExtendedTest.kt +++ b/backend/src/test/kotlin/com/moneat/services/MonitorServiceExtendedTest.kt @@ -127,18 +127,18 @@ class MonitorServiceExtendedTest { val metrics = service.getLatestMetrics(1) assertNotNull(metrics) - assertEquals(75.5f, metrics.cpu_percent) - assertEquals(8589934592L, metrics.mem_total) + assertEquals(75.5f, metrics.cpuPercent) + assertEquals(8589934592L, metrics.memTotal) // mem_used = memTotal - memAvailable = 8589934592 - 4294967296 = 4294967296 - assertEquals(4294967296L, metrics.mem_used) - assertEquals(107374182400L, metrics.disk_total) - assertEquals(53687091200L, metrics.disk_used) - assertEquals(123456L, metrics.net_recv_bytes) - assertEquals(654321L, metrics.net_sent_bytes) - assertEquals(1.5f, metrics.load_1) - assertEquals(62.0f, metrics.temp_max) - assertEquals(45.0f, metrics.gpu_percent) - assertEquals(85.0f, metrics.battery_percent) + assertEquals(4294967296L, metrics.memUsed) + assertEquals(107374182400L, metrics.diskTotal) + assertEquals(53687091200L, metrics.diskUsed) + assertEquals(123456L, metrics.netRecvBytes) + assertEquals(654321L, metrics.netSentBytes) + assertEquals(1.5f, metrics.load1) + assertEquals(62.0f, metrics.tempMax) + assertEquals(45.0f, metrics.gpuPercent) + assertEquals(85.0f, metrics.batteryPercent) } @Test @@ -172,8 +172,8 @@ class MonitorServiceExtendedTest { val metrics = service.getLatestMetrics(1) assertNotNull(metrics) - assertEquals(400L, metrics.mem_used) - assertEquals(40.0f, metrics.mem_percent) + assertEquals(400L, metrics.memUsed) + assertEquals(40.0f, metrics.memPercent) } @Test @@ -189,7 +189,7 @@ class MonitorServiceExtendedTest { val metrics = service.getLatestMetrics(1) assertNotNull(metrics) - assertEquals(800L, metrics.mem_used) + assertEquals(800L, metrics.memUsed) } @Test @@ -237,9 +237,9 @@ class MonitorServiceExtendedTest { val result = service.getLatestMetricsForHosts(listOf(1, 2, 3), 10) assertEquals(3, result.size) assertNotNull(result[1]) - assertEquals(80.0f, result[1]?.cpu_percent) + assertEquals(80.0f, result[1]?.cpuPercent) assertNotNull(result[2]) - assertEquals(60.0f, result[2]?.cpu_percent) + assertEquals(60.0f, result[2]?.cpuPercent) assertNull(result[3]) } @@ -292,11 +292,11 @@ class MonitorServiceExtendedTest { assertEquals("abc123", containers[0].id) assertEquals("nginx:latest", containers[0].image) assertEquals("running", containers[0].status) - assertEquals(25.5f, containers[0].cpu_percent) - assertEquals(524288000L, containers[0].mem_used) - assertEquals(1073741824L, containers[0].mem_limit) - assertEquals(12345L, containers[0].net_recv_bytes) - assertEquals(67890L, containers[0].net_sent_bytes) + assertEquals(25.5f, containers[0].cpuPercent) + assertEquals(524288000L, containers[0].memUsed) + assertEquals(1073741824L, containers[0].memLimit) + assertEquals(12345L, containers[0].netRecvBytes) + assertEquals(67890L, containers[0].netSentBytes) } @Test @@ -317,7 +317,7 @@ class MonitorServiceExtendedTest { """.trimIndent() val containers = service.getLatestContainers(1) - assertEquals(50.0f, containers[0].mem_percent) + assertEquals(50.0f, containers[0].memPercent) } @Test @@ -370,8 +370,8 @@ class MonitorServiceExtendedTest { every { hostRepo.getById(999) } returns null val result = service.getHistoricalMetrics(999, 1000, 2000, null) - assertTrue(result.data_points.isEmpty()) - assertEquals(999, result.host_id) + assertTrue(result.dataPoints.isEmpty()) + assertEquals(999, result.hostId) } @Test @@ -383,7 +383,7 @@ class MonitorServiceExtendedTest { val nowEpoch = Clock.System.now().epochSeconds val farPast = nowEpoch - 86400L * 30 val result = service.getHistoricalMetrics(1, farPast, farPast + 100, null) - assertTrue(result.data_points.isEmpty()) + assertTrue(result.dataPoints.isEmpty()) } @Test @@ -401,8 +401,8 @@ class MonitorServiceExtendedTest { nowEpoch, null ) - assertEquals(10, result.interval_seconds) - assertTrue(result.data_points.isEmpty()) + assertEquals(10, result.intervalSeconds) + assertTrue(result.dataPoints.isEmpty()) } @Test @@ -413,7 +413,7 @@ class MonitorServiceExtendedTest { coEvery { hostRepo.executeClickHouseQuery(any()) } returns DATA_EMPTY_JSON val result = service.getHistoricalMetrics(1, nowEpoch - 3600, nowEpoch, 120) - assertEquals(120, result.interval_seconds) + assertEquals(120, result.intervalSeconds) } @Test @@ -433,10 +433,10 @@ class MonitorServiceExtendedTest { """.trimIndent() val result = service.getHistoricalMetrics(1, nowEpoch - 3600, nowEpoch, 60) - assertEquals(2, result.data_points.size) - assertEquals(55.0f, result.data_points[0].cpu_percent) - assertEquals(70.0f, result.data_points[0].mem_percent) - assertEquals(60.0f, result.data_points[1].cpu_percent) + assertEquals(2, result.dataPoints.size) + assertEquals(55.0f, result.dataPoints[0].cpuPercent) + assertEquals(70.0f, result.dataPoints[0].memPercent) + assertEquals(60.0f, result.dataPoints[1].cpuPercent) } // ──── getContainerHistoricalMetrics ──── @@ -446,8 +446,8 @@ class MonitorServiceExtendedTest { every { hostRepo.getById(999) } returns null val result = service.getContainerHistoricalMetrics(999, "nginx", 1000, 2000, null) - assertTrue(result.data_points.isEmpty()) - assertEquals("nginx", result.container_name) + assertTrue(result.dataPoints.isEmpty()) + assertEquals("nginx", result.containerName) } @Test @@ -457,7 +457,7 @@ class MonitorServiceExtendedTest { val farPast = Clock.System.now().epochSeconds - 86400L * 30 val result = service.getContainerHistoricalMetrics(1, "nginx", farPast, farPast + 100, null) - assertTrue(result.data_points.isEmpty()) + assertTrue(result.dataPoints.isEmpty()) } @Test @@ -482,10 +482,10 @@ class MonitorServiceExtendedTest { nowEpoch, 60 ) - assertEquals(1, result.data_points.size) - assertEquals(25.0f, result.data_points[0].cpu_percent) - assertEquals(524288000L, result.data_points[0].mem_used) - assertEquals(1073741824L, result.data_points[0].mem_limit) + assertEquals(1, result.dataPoints.size) + assertEquals(25.0f, result.dataPoints[0].cpuPercent) + assertEquals(524288000L, result.dataPoints[0].memUsed) + assertEquals(1073741824L, result.dataPoints[0].memLimit) } // ──── getLatestInfraContainers ──── diff --git a/backend/src/test/kotlin/com/moneat/services/NotificationFormattingTest.kt b/backend/src/test/kotlin/com/moneat/services/NotificationFormattingTest.kt index 70dc52e97..64e93d37a 100644 --- a/backend/src/test/kotlin/com/moneat/services/NotificationFormattingTest.kt +++ b/backend/src/test/kotlin/com/moneat/services/NotificationFormattingTest.kt @@ -124,7 +124,7 @@ class NotificationFormattingTest { val element = SlackService.SlackElement( type = "button", text = SlackService.SlackText(type = "plain_text", text = "Click"), - action_id = "btn_click" + actionId = "btn_click" ) val encoded = json.encodeToString(element) val obj = Json.parseToJsonElement(encoded).jsonObject @@ -188,7 +188,7 @@ class NotificationFormattingTest { val response = json.decodeFromString(responseJson) assertTrue(response.ok) - assertEquals("xoxb-123", response.access_token) + assertEquals("xoxb-123", response.accessToken) assertEquals("T123", response.team?.id) assertEquals("Test Team", response.team?.name) } @@ -200,7 +200,7 @@ class NotificationFormattingTest { assertEquals(false, response.ok) assertEquals("invalid_code", response.error) - assertNull(response.access_token) + assertNull(response.accessToken) } @Test @@ -235,7 +235,7 @@ class NotificationFormattingTest { assertTrue(response.ok) assertEquals(2, response.channels?.size) assertEquals("C001", response.channels?.get(0)?.id) - assertEquals(true, response.channels?.get(1)?.is_private) + assertEquals(true, response.channels?.get(1)?.isPrivate) } @Test @@ -395,8 +395,8 @@ class NotificationFormattingTest { """.trimIndent() val response = json.decodeFromString(responseJson) - assertEquals("abc123", response.access_token) - assertEquals("Bearer", response.token_type) + assertEquals("abc123", response.accessToken) + assertEquals("Bearer", response.tokenType) assertEquals("G123", response.guild?.id) assertEquals("Test Guild", response.guild?.name) assertNull(response.error) @@ -408,7 +408,7 @@ class NotificationFormattingTest { val response = json.decodeFromString(responseJson) assertEquals("invalid_grant", response.error) - assertNull(response.access_token) + assertNull(response.accessToken) assertNull(response.guild) } diff --git a/backend/src/test/kotlin/com/moneat/services/NotificationServiceRoutingTest.kt b/backend/src/test/kotlin/com/moneat/services/NotificationServiceRoutingTest.kt index cfb4bf54f..f6dd0347d 100644 --- a/backend/src/test/kotlin/com/moneat/services/NotificationServiceRoutingTest.kt +++ b/backend/src/test/kotlin/com/moneat/services/NotificationServiceRoutingTest.kt @@ -163,7 +163,7 @@ class NotificationServiceRoutingTest { environment: String? = "production" ): SentryEvent = SentryEvent( - event_id = eventId, + eventId = eventId, timestamp = Clock.System.now().toEpochMilliseconds() / 1000.0, level = level, message = message, @@ -172,7 +172,7 @@ class NotificationServiceRoutingTest { private fun buildEventWithException(): SentryEvent = SentryEvent( - event_id = "evt-exc-1", + eventId = "evt-exc-1", timestamp = Clock.System.now().toEpochMilliseconds() / 1000.0, level = "error", message = null, @@ -188,13 +188,13 @@ class NotificationServiceRoutingTest { filename = "UserService.kt", function = "getUser", lineno = 42, - in_app = true + inApp = true ), StackFrame( filename = "UserRoute.kt", function = "handleGet", lineno = 15, - in_app = true + inApp = true ) ) ) @@ -521,7 +521,7 @@ class NotificationServiceRoutingTest { seedNotificationPrefs(userId, frequencyMinutes = 0) val event = SentryEvent( - event_id = "evt-nots", + eventId = "evt-nots", timestamp = null, level = "error", message = "Timestamp-less error" diff --git a/backend/src/test/kotlin/com/moneat/services/NotificationServiceTest.kt b/backend/src/test/kotlin/com/moneat/services/NotificationServiceTest.kt index b99008232..099a0fbff 100644 --- a/backend/src/test/kotlin/com/moneat/services/NotificationServiceTest.kt +++ b/backend/src/test/kotlin/com/moneat/services/NotificationServiceTest.kt @@ -112,7 +112,7 @@ class NotificationServiceTest { try { val event = SentryEvent( - event_id = "evt-1", + eventId = "evt-1", timestamp = Clock.System.now().toEpochMilliseconds() / 1000.0, level = "error", message = "NullPointerException in checkout flow", @@ -123,7 +123,7 @@ class NotificationServiceTest { waitForEmailRows(expectedCount = 1) // Second issue alert for the same project/user should be throttled by alert frequency. - notificationService.onNewIssue(projectId, "1002", event.copy(event_id = "evt-2")) + notificationService.onNewIssue(projectId, "1002", event.copy(eventId = "evt-2")) waitForEmailRows(expectedCount = 1) val sentRows = diff --git a/backend/src/test/kotlin/com/moneat/services/SummaryServiceTest.kt b/backend/src/test/kotlin/com/moneat/services/SummaryServiceTest.kt index 230379647..bfaf98499 100644 --- a/backend/src/test/kotlin/com/moneat/services/SummaryServiceTest.kt +++ b/backend/src/test/kotlin/com/moneat/services/SummaryServiceTest.kt @@ -208,21 +208,21 @@ class SummaryServiceTest { cpu: Float = 55.0f, mem: Float = 70.0f ): LatestMetrics = LatestMetrics( - cpu_percent = cpu, - mem_total = 16000000L, - mem_used = 11200000L, - mem_percent = mem, - disk_total = 500000000L, - disk_used = 250000000L, - disk_percent = 50.0f, - net_recv_bytes = 1000L, - net_sent_bytes = 2000L, - net_recv_mbps = 1.0f, - net_sent_mbps = 2.0f, - load_1 = 1.5f, - temp_max = null, - gpu_percent = null, - battery_percent = null + cpuPercent = cpu, + memTotal = 16000000L, + memUsed = 11200000L, + memPercent = mem, + diskTotal = 500000000L, + diskUsed = 250000000L, + diskPercent = 50.0f, + netRecvBytes = 1000L, + netSentBytes = 2000L, + netRecvMbps = 1.0f, + netSentMbps = 2.0f, + load1 = 1.5f, + tempMax = null, + gpuPercent = null, + batteryPercent = null ) private fun mockClickHouseHandler( diff --git a/ee/backend/detekt.yml b/ee/backend/detekt.yml index a273ceee6..b768b503a 100644 --- a/ee/backend/detekt.yml +++ b/ee/backend/detekt.yml @@ -66,7 +66,7 @@ naming: MatchingDeclarationName: active: false ConstructorParameterNaming: - active: false + active: true FunctionNaming: active: false VariableNaming: diff --git a/ee/backend/src/main/kotlin/com/moneat/enterprise/ai/llm/providers/AnthropicProvider.kt b/ee/backend/src/main/kotlin/com/moneat/enterprise/ai/llm/providers/AnthropicProvider.kt index 90f64b652..c4f799aa0 100644 --- a/ee/backend/src/main/kotlin/com/moneat/enterprise/ai/llm/providers/AnthropicProvider.kt +++ b/ee/backend/src/main/kotlin/com/moneat/enterprise/ai/llm/providers/AnthropicProvider.kt @@ -47,7 +47,7 @@ class AnthropicProvider : LlmProvider { val request = AnthropicRequest( model = modelName, - max_tokens = minOf(config.maxTokens, maxTokensCfg), + maxTokens = minOf(config.maxTokens, maxTokensCfg), system = systemText.ifBlank { null }, messages = conversationMessages, ) @@ -70,8 +70,8 @@ class AnthropicProvider : LlmProvider { return LlmResponse( content = textContent, - inputTokens = parsed.usage?.input_tokens ?: 0, - outputTokens = parsed.usage?.output_tokens ?: 0, + inputTokens = parsed.usage?.inputTokens ?: 0, + outputTokens = parsed.usage?.outputTokens ?: 0, model = modelName, provider = "anthropic", ) @@ -82,14 +82,17 @@ class AnthropicProvider : LlmProvider { @Serializable data class AnthropicRequest( val model: String, - val max_tokens: Int, + @SerialName("max_tokens") val maxTokens: Int, val system: String? = null, val messages: List, ) @Serializable data class AnthropicContentBlock(val type: String, val text: String = "") - @Serializable data class AnthropicUsage(val input_tokens: Int = 0, val output_tokens: Int = 0) + @Serializable data class AnthropicUsage( + @SerialName("input_tokens") val inputTokens: Int = 0, + @SerialName("output_tokens") val outputTokens: Int = 0, + ) @Serializable data class AnthropicResponse( val id: String = "", diff --git a/ee/backend/src/main/kotlin/com/moneat/enterprise/ai/llm/providers/OpenAiProvider.kt b/ee/backend/src/main/kotlin/com/moneat/enterprise/ai/llm/providers/OpenAiProvider.kt index ea9a333e0..79a2b53e4 100644 --- a/ee/backend/src/main/kotlin/com/moneat/enterprise/ai/llm/providers/OpenAiProvider.kt +++ b/ee/backend/src/main/kotlin/com/moneat/enterprise/ai/llm/providers/OpenAiProvider.kt @@ -16,6 +16,7 @@ import io.ktor.client.request.* import io.ktor.client.statement.* import io.ktor.http.* import io.ktor.serialization.kotlinx.json.* +import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable import kotlinx.serialization.json.Json import mu.KotlinLogging @@ -41,9 +42,9 @@ class OpenAiProvider : LlmProvider { val request = OpenAiRequest( model = modelName, messages = messages.map { OpenAiMsg(it.role, it.content) }, - max_tokens = config.maxTokens, + maxTokens = config.maxTokens, temperature = config.temperature, - response_format = if (config.jsonMode) OpenAiFormat("json_object") else null, + responseFormat = if (config.jsonMode) OpenAiFormat("json_object") else null, ) val response = client.post("https://api.openai.com/v1/chat/completions") { @@ -62,8 +63,8 @@ class OpenAiProvider : LlmProvider { val choice = parsed.choices.firstOrNull() return LlmResponse( content = choice?.message?.content ?: "", - inputTokens = parsed.usage?.prompt_tokens ?: 0, - outputTokens = parsed.usage?.completion_tokens ?: 0, + inputTokens = parsed.usage?.promptTokens ?: 0, + outputTokens = parsed.usage?.completionTokens ?: 0, model = modelName, provider = "openai", ) @@ -77,18 +78,21 @@ class OpenAiProvider : LlmProvider { @Serializable data class OpenAiRequest( val model: String, val messages: List, - val max_tokens: Int = 4096, + @SerialName("max_tokens") val maxTokens: Int = 4096, val temperature: Double = 0.3, - val response_format: OpenAiFormat? = null, + @SerialName("response_format") val responseFormat: OpenAiFormat? = null, ) - @Serializable data class OpenAiChoice(val message: OpenAiMsg, val finish_reason: String? = null) + @Serializable data class OpenAiChoice( + val message: OpenAiMsg, + @SerialName("finish_reason") val finishReason: String? = null, + ) @Serializable data class OpenAiUsage( - val prompt_tokens: Int = 0, - val completion_tokens: Int = 0, - val total_tokens: Int = 0, + @SerialName("prompt_tokens") val promptTokens: Int = 0, + @SerialName("completion_tokens") val completionTokens: Int = 0, + @SerialName("total_tokens") val totalTokens: Int = 0, ) @Serializable diff --git a/ee/backend/src/main/kotlin/com/moneat/enterprise/mcp/services/SummaryService.kt b/ee/backend/src/main/kotlin/com/moneat/enterprise/mcp/services/SummaryService.kt index a667366c4..c46b16bb7 100644 --- a/ee/backend/src/main/kotlin/com/moneat/enterprise/mcp/services/SummaryService.kt +++ b/ee/backend/src/main/kotlin/com/moneat/enterprise/mcp/services/SummaryService.kt @@ -265,8 +265,8 @@ class SummaryService( HostMetricSnapshot( systemId = sys.id.toString(), systemName = sys.displayName ?: sys.hostname, - cpuPercent = metrics?.cpu_percent, - memPercent = metrics?.mem_percent, + cpuPercent = metrics?.cpuPercent, + memPercent = metrics?.memPercent, status = sys.status, ) } From f40cd81a92a1c8a4ca8ac568b0ba07bf4dccba59 Mon Sep 17 00:00:00 2001 From: Adrian Elder Date: Sun, 29 Mar 2026 21:10:22 -0400 Subject: [PATCH 2/2] fix: address CodeRabbit feedback (round 1) for #324 --- .../kotlin/com/moneat/events/services/EventService.kt | 6 +++--- .../kotlin/com/moneat/monitor/services/MonitorService.kt | 8 ++++---- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/backend/src/main/kotlin/com/moneat/events/services/EventService.kt b/backend/src/main/kotlin/com/moneat/events/services/EventService.kt index fd5e3eaeb..d7f6732d9 100644 --- a/backend/src/main/kotlin/com/moneat/events/services/EventService.kt +++ b/backend/src/main/kotlin/com/moneat/events/services/EventService.kt @@ -627,10 +627,10 @@ class EventService( private fun syntheticReplayMetadataFromEnvelope(envelope: SentryEnvelope): SyntheticReplayMetadata { val fallback = SyntheticReplayMetadata( - sdkName = "sentry.java.android", + sdkName = "", sdkVersion = "", - platform = "android", - environment = "e2e-testing", + platform = "", + environment = "", release = "", ) for (item in envelope.items) { diff --git a/backend/src/main/kotlin/com/moneat/monitor/services/MonitorService.kt b/backend/src/main/kotlin/com/moneat/monitor/services/MonitorService.kt index 0627938c1..b15b5e712 100644 --- a/backend/src/main/kotlin/com/moneat/monitor/services/MonitorService.kt +++ b/backend/src/main/kotlin/com/moneat/monitor/services/MonitorService.kt @@ -338,7 +338,7 @@ class MonitorService( MONITOR_HISTORY_CACHE_TTL_SECONDS ) { val host = getHostById(hostId) ?: return@cached HistoricalMetricsResponse( - systemId = "", + systemId = hostId.toString(), hostId = hostId, from = fromTimestamp, to = toTimestamp, @@ -348,7 +348,7 @@ class MonitorService( val clampedWindow = clampRangeToRetention(hostId, fromTimestamp, toTimestamp) if (clampedWindow == null) { return@cached HistoricalMetricsResponse( - systemId = "", + systemId = hostId.toString(), hostId = hostId, from = fromTimestamp, to = toTimestamp, @@ -403,7 +403,7 @@ class MonitorService( val result = json.parseToJsonElement(body).jsonObject val data = result["data"]?.jsonArray ?: return@cached HistoricalMetricsResponse( - systemId = "", + systemId = hostId.toString(), hostId = hostId, from = effectiveFrom, to = effectiveTo, @@ -444,7 +444,7 @@ class MonitorService( } HistoricalMetricsResponse( - systemId = "", + systemId = hostId.toString(), hostId = hostId, from = effectiveFrom, to = effectiveTo,