一键导入
observability
OpenTelemetry-tracing via TraceUtils.withTracerId, MDC-propagering, x-correlation-id og TEAM_LOGS_MARKER-konvensjoner for sensitive data
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
菜单
OpenTelemetry-tracing via TraceUtils.withTracerId, MDC-propagering, x-correlation-id og TEAM_LOGS_MARKER-konvensjoner for sensitive data
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
基于 SOC 职业分类
Flyway-migrasjoner for PostgreSQL: navnekonvensjoner (V{n}__desc.sql), skjema for krav/feilmelding/filvalideringsfeil, DBListener-testing med TestContainers
Post-send livssyklus: StatusService poller /mottaksstatus; StoppKravService; RapportService + AvstemmingRouting-frontend for manuell reskontroføring
HOCON-basert konfigurasjon med PropertiesConfig singleton for Ktor batch-tjenester på NAIS (FSS)
SlackService feilakkumulering og Tags-basert varsling for prosesseringsfeil i SKE-batch
Endring av eksisterende krav (endre rente og endre hovedstol): EndreKravService, request-DTOer, status-konformering og SKE API PUT-endepunkter
Kotest BehaviorSpec/MockK-mønstre for sokos-ske-krav: scenariostruktur, DBListener/SftpListener, MockHttpClient, circuit-breaker-reset og matchers
| name | observability |
| description | OpenTelemetry-tracing via TraceUtils.withTracerId, MDC-propagering, x-correlation-id og TEAM_LOGS_MARKER-konvensjoner for sensitive data |
All async work in the service runs inside a TraceUtils.withTracerId { } block so that logs and metrics can be correlated end-to-end across an SFTP-batch run.
TraceUtils.withTracerIdobject TraceUtils {
suspend fun <T> withTracerId(
tracer: Tracer = openTelemetry.getTracer(this::class.java.canonicalName),
spanName: String = "withTracerId",
forceNewTrace: Boolean = false,
block: suspend () -> T,
): T {
val span = tracer.spanBuilder(spanName)
.apply { if (forceNewTrace) setNoParent() }
.startSpan()
return Context.current().with(span).makeCurrent().use {
try {
MDC.put(LoggingContextConstants.TRACE_ID, span.spanContext.traceId)
MDC.put(LoggingContextConstants.SPAN_ID, span.spanContext.spanId)
val r = block(); span.setStatus(StatusCode.OK); r
} catch (e: Exception) {
span.setStatus(StatusCode.ERROR, e.message ?: "Unknown error")
span.recordException(e); throw e
} finally {
MDC.remove(LoggingContextConstants.TRACE_ID)
MDC.remove(LoggingContextConstants.SPAN_ID)
span.end()
}
}
}
}
TraceUtils.withTracerId(spanName = "handleNewKrav", forceNewTrace = true) { ... }.TraceUtils.withTracerId(spanName = "fil:$filnavn") { ... }.withTracerId is suspend-friendly and sets MDC on the current coroutine context — log statements inside the block will get trace_id / span_id automatically.MDC.put directly for tracing — always go through withTracerId.Every request to SKE carries x-correlation-id: ${krav.corrId}. corrId is assigned on insert (Krav.corrId = UUID.randomUUID().toString()) and is the same for both ENDRING_HOVEDSTOL and ENDRING_RENTE rows of the same endring. The header is appended by SkeClient.doPost / doPut — do not add it manually in service code.
TEAM_LOGS_MARKER (defined in config/CommonConfig.kt) routes log statements to a restricted-access sink suitable for PII. Must be used for anything that touches:
gjelderId (fnr / orgnr), saksnummerNAV, full request/response bodieslogger.error(marker = TEAM_LOGS_MARKER) {
"Feil for saksnummer: $saksnummer - body=$body"
}
Regular logger.info { ... } without a marker → public Grafana Loki. Assume anyone in NAV can read it.
TraceUtils.withTracerId(forceNewTrace = true)withTracerId with a meaningful spanNameTEAM_LOGS_MARKER for any log containing PII, tokens, or raw request/response bodiesSkeClient set x-correlation-id — never add it manuallyMDC.put(TRACE_ID / SPAN_ID) outside TraceUtilsaccess_token, private keys, or raw JWT assertions at any levelTEAM_LOGS_MARKERcorrId across unrelated krav