diff --git a/.dockerignore b/.dockerignore index b27bee7..17225da 100644 --- a/.dockerignore +++ b/.dockerignore @@ -1,3 +1,4 @@ +Makefile .gradle .idea build diff --git a/Dockerfile b/Dockerfile index 5417e6d..9c81b8e 100644 --- a/Dockerfile +++ b/Dockerfile @@ -33,10 +33,15 @@ COPY --from=build /src/build/distributions/app.tar $APP_ROOT/ RUN mkdir $APP_ROOT/run RUN tar -xvf app.tar --strip-components=1 -C $APP_ROOT/run +# ------------------- Wire common ----------------- # create version file ARG release_version=development ENV RELEASE_FILE_PATH=$APP_ROOT/run/release.txt RUN echo $release_version > $RELEASE_FILE_PATH +# enable json logging +# TODO enable this once we fully migrate to JSON logging everywhere +# ENV JSON_LOGGING=true +# /------------------ Wire common ----------------- EXPOSE 8080 ENTRYPOINT ["/bin/sh", "-c", "/app/run/bin/polls"] diff --git a/build.gradle.kts b/build.gradle.kts index 7779edc..3410f77 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,17 +1,17 @@ plugins { - kotlin("jvm") version "1.3.71" + kotlin("jvm") version "1.4.10" application distribution - id("net.nemerosa.versioning") version "2.12.1" + id("net.nemerosa.versioning") version "2.14.0" } group = "com.wire.bots.polls" version = versioning.info?.tag ?: versioning.info?.lastTag ?: "development" -val mainClass = "com.wire.bots.polls.PollBotKt" +val mClass = "com.wire.bots.polls.PollBotKt" application { - mainClassName = mainClass + mainClass.set(mClass) } repositories { @@ -22,10 +22,11 @@ dependencies { // stdlib implementation(kotlin("stdlib-jdk8")) // extension functions - implementation("ai.blindspot.ktoolz", "ktoolz", "1.0.6") + implementation("pw.forst.tools", "katlib", "1.1.2") + // Ktor server dependencies - val ktorVersion = "1.3.2" + val ktorVersion = "1.4.1" implementation("io.ktor", "ktor-server-core", ktorVersion) implementation("io.ktor", "ktor-server-netty", ktorVersion) implementation("io.ktor", "ktor-jackson", ktorVersion) @@ -39,21 +40,23 @@ dependencies { // Prometheus metrics implementation("io.ktor", "ktor-metrics-micrometer", ktorVersion) - implementation("io.micrometer", "micrometer-registry-prometheus", "1.4.1") + implementation("io.micrometer", "micrometer-registry-prometheus", "1.5.5") // logging - implementation("io.github.microutils", "kotlin-logging", "1.7.9") + implementation("io.github.microutils", "kotlin-logging", "2.0.3") + // if-else in logback.xml + implementation("org.codehaus.janino", "janino", "3.1.2") implementation("ch.qos.logback", "logback-classic", "1.2.3") // DI - val kodeinVersion = "6.5.4" + val kodeinVersion = "6.5.5" implementation("org.kodein.di", "kodein-di-generic-jvm", kodeinVersion) implementation("org.kodein.di", "kodein-di-framework-ktor-server-jvm", kodeinVersion) // database implementation("org.postgresql", "postgresql", "42.2.2") - val exposedVersion = "0.22.1" + val exposedVersion = "0.27.1" implementation("org.jetbrains.exposed", "exposed-core", exposedVersion) implementation("org.jetbrains.exposed", "exposed-dao", exposedVersion) implementation("org.jetbrains.exposed", "exposed-jdbc", exposedVersion) @@ -61,7 +64,7 @@ dependencies { implementation("pw.forst", "exposed-upsert", "1.0") // database migrations from the code - implementation("org.flywaydb", "flyway-core", "6.3.2") + implementation("org.flywaydb", "flyway-core", "7.0.0") } tasks { @@ -82,7 +85,7 @@ tasks { register("fatJar") { manifest { - attributes["Main-Class"] = mainClass + attributes["Main-Class"] = mClass } duplicatesStrategy = DuplicatesStrategy.EXCLUDE archiveFileName.set("polls.jar") diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index a4b4429..6c9a224 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-6.3-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-6.6-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/integrationTests/src/main/kotlin/com/wire/bots/polls/integration_tests/routing/Routing.kt b/integrationTests/src/main/kotlin/com/wire/bots/polls/integration_tests/routing/Routing.kt index bbf3f10..3b6c58c 100644 --- a/integrationTests/src/main/kotlin/com/wire/bots/polls/integration_tests/routing/Routing.kt +++ b/integrationTests/src/main/kotlin/com/wire/bots/polls/integration_tests/routing/Routing.kt @@ -1,6 +1,6 @@ package com.wire.bots.polls.integration_tests.routing -import ai.blindspot.ktoolz.extensions.whenNull +import pw.forst.tools.katlib.whenNull import com.wire.bots.polls.integration_tests.dto.Conversation import com.wire.bots.polls.integration_tests.dto.ProxyResponseMessage import com.wire.bots.polls.integration_tests.store.tokenStorage diff --git a/integrationTests/src/main/kotlin/com/wire/bots/polls/integration_tests/setup/ConfigurationDependencyInjection.kt b/integrationTests/src/main/kotlin/com/wire/bots/polls/integration_tests/setup/ConfigurationDependencyInjection.kt index 46fe7c7..dedea67 100644 --- a/integrationTests/src/main/kotlin/com/wire/bots/polls/integration_tests/setup/ConfigurationDependencyInjection.kt +++ b/integrationTests/src/main/kotlin/com/wire/bots/polls/integration_tests/setup/ConfigurationDependencyInjection.kt @@ -1,7 +1,7 @@ package com.wire.bots.polls.integration_tests.setup -import ai.blindspot.ktoolz.extensions.getEnv -import ai.blindspot.ktoolz.extensions.whenNull +import pw.forst.tools.katlib.getEnv +import pw.forst.tools.katlib.whenNull import com.wire.bots.polls.integration_tests.dto.BotApiConfiguration import com.wire.bots.polls.integration_tests.setup.EnvConfigVariables.BOT_API import com.wire.bots.polls.integration_tests.setup.EnvConfigVariables.SERVICE_TOKEN diff --git a/integrationTests/src/test/kotlin/com/wire/bots/polls/integration_tests/FlowTest.kt b/integrationTests/src/test/kotlin/com/wire/bots/polls/integration_tests/FlowTest.kt index c829581..eeae656 100644 --- a/integrationTests/src/test/kotlin/com/wire/bots/polls/integration_tests/FlowTest.kt +++ b/integrationTests/src/test/kotlin/com/wire/bots/polls/integration_tests/FlowTest.kt @@ -1,6 +1,6 @@ package com.wire.bots.polls.integration_tests -import ai.blindspot.ktoolz.extensions.newLine +import pw.forst.tools.katlib.newLine import com.wire.bots.polls.integration_tests.dto.botRequest import com.wire.bots.polls.integration_tests.dto.init import com.wire.bots.polls.integration_tests.dto.reaction diff --git a/src/main/kotlin/com/wire/bots/polls/dao/PollRepository.kt b/src/main/kotlin/com/wire/bots/polls/dao/PollRepository.kt index 34841b2..f7ff8c4 100644 --- a/src/main/kotlin/com/wire/bots/polls/dao/PollRepository.kt +++ b/src/main/kotlin/com/wire/bots/polls/dao/PollRepository.kt @@ -1,6 +1,5 @@ package com.wire.bots.polls.dao -import ai.blindspot.ktoolz.extensions.mapToSet import com.wire.bots.polls.dto.PollAction import com.wire.bots.polls.dto.PollDto import com.wire.bots.polls.dto.Question @@ -14,6 +13,7 @@ import org.jetbrains.exposed.sql.insert import org.jetbrains.exposed.sql.select import org.jetbrains.exposed.sql.transactions.experimental.newSuspendedTransaction import pw.forst.exposed.insertOrUpdate +import pw.forst.tools.katlib.mapToSet /** * Simple repository for handling database transactions on one place. diff --git a/src/main/kotlin/com/wire/bots/polls/parser/PollFactory.kt b/src/main/kotlin/com/wire/bots/polls/parser/PollFactory.kt index 2c7f79a..6199387 100644 --- a/src/main/kotlin/com/wire/bots/polls/parser/PollFactory.kt +++ b/src/main/kotlin/com/wire/bots/polls/parser/PollFactory.kt @@ -1,10 +1,10 @@ package com.wire.bots.polls.parser -import ai.blindspot.ktoolz.extensions.newLine -import ai.blindspot.ktoolz.extensions.whenNull import com.wire.bots.polls.dto.PollDto import com.wire.bots.polls.dto.UsersInput import mu.KLogging +import pw.forst.tools.katlib.newLine +import pw.forst.tools.katlib.whenNull /** * Class used for creating the polls from the text. Parsing and creating the poll objects. diff --git a/src/main/kotlin/com/wire/bots/polls/routing/MessagesRoute.kt b/src/main/kotlin/com/wire/bots/polls/routing/MessagesRoute.kt index 3d4404f..955b438 100644 --- a/src/main/kotlin/com/wire/bots/polls/routing/MessagesRoute.kt +++ b/src/main/kotlin/com/wire/bots/polls/routing/MessagesRoute.kt @@ -3,6 +3,8 @@ package com.wire.bots.polls.routing import com.wire.bots.polls.dto.roman.Message import com.wire.bots.polls.services.AuthService import com.wire.bots.polls.services.MessagesHandlingService +import com.wire.bots.polls.setup.logging.USER_ID +import com.wire.bots.polls.utils.mdc import io.ktor.application.call import io.ktor.http.HttpStatusCode import io.ktor.request.receive @@ -36,6 +38,9 @@ fun Routing.messages(k: LazyKodein) { call.respond(HttpStatusCode.BadRequest, "Bot did not understand the message.") }.onSuccess { routingLogger.debug { "Message parsed." } + // includes user id to current MDC + mdc(USER_ID) { it.userId } + handler.handle(it) routingLogger.debug { "Responding OK" } call.respond(HttpStatusCode.OK) diff --git a/src/main/kotlin/com/wire/bots/polls/services/AuthService.kt b/src/main/kotlin/com/wire/bots/polls/services/AuthService.kt index 34c43ad..31197ea 100644 --- a/src/main/kotlin/com/wire/bots/polls/services/AuthService.kt +++ b/src/main/kotlin/com/wire/bots/polls/services/AuthService.kt @@ -1,8 +1,8 @@ package com.wire.bots.polls.services -import ai.blindspot.ktoolz.extensions.whenNull import io.ktor.http.Headers import mu.KLogging +import pw.forst.tools.katlib.whenNull /** * Authentication service. diff --git a/src/main/kotlin/com/wire/bots/polls/services/PollService.kt b/src/main/kotlin/com/wire/bots/polls/services/PollService.kt index 395fa6e..0df5bc1 100644 --- a/src/main/kotlin/com/wire/bots/polls/services/PollService.kt +++ b/src/main/kotlin/com/wire/bots/polls/services/PollService.kt @@ -1,16 +1,14 @@ package com.wire.bots.polls.services -import ai.blindspot.ktoolz.extensions.whenNull -import ai.blindspot.ktoolz.extensions.whenTrue import com.wire.bots.polls.dao.PollRepository import com.wire.bots.polls.dto.PollAction import com.wire.bots.polls.dto.UsersInput import com.wire.bots.polls.dto.bot.confirmVote import com.wire.bots.polls.dto.bot.newPoll import com.wire.bots.polls.parser.PollFactory -import kotlinx.coroutines.GlobalScope -import kotlinx.coroutines.launch import mu.KLogging +import pw.forst.tools.katlib.whenNull +import pw.forst.tools.katlib.whenTrue import java.util.UUID /** @@ -40,21 +38,18 @@ class PollService( val pollId = repository.savePoll(poll, pollId = UUID.randomUUID().toString(), userId = usersInput.userId, botSelfId = botId) logger.info { "Poll successfully created with id: $pollId" } - // send response with async way - GlobalScope.launch { - proxySenderService.send( - token, - message = newPoll( - id = pollId, - body = poll.question.body, - buttons = poll.options, - mentions = poll.question.mentions - ) - ).whenNull { - logger.error { "It was not possible to send the poll to the Roman!" } - }?.also { (messageId) -> - logger.info { "Poll successfully created with id: $messageId" } - } + proxySenderService.send( + token, + message = newPoll( + id = pollId, + body = poll.question.body, + buttons = poll.options, + mentions = poll.question.mentions + ) + ).whenNull { + logger.error { "It was not possible to send the poll to the Roman!" } + }?.also { (messageId) -> + logger.info { "Poll successfully created with id: $messageId" } } return pollId @@ -63,10 +58,8 @@ class PollService( private suspend fun pollNotParsedFallback(token: String, usersInput: UsersInput) { usersInput.input.startsWith("/poll").whenTrue { - GlobalScope.launch { - logger.info { "Command started with /poll, sending usage to user." } - userCommunicationService.reactionToWrongCommand(token) - } + logger.info { "Command started with /poll, sending usage to user." } + userCommunicationService.reactionToWrongCommand(token) } } @@ -79,20 +72,18 @@ class PollService( repository.vote(pollAction) logger.info { "Vote registered." } - GlobalScope.launch { - proxySenderService.send( - token = token, - message = confirmVote( - pollId = pollAction.pollId, - offset = pollAction.optionId, - userId = pollAction.userId - ) - ).whenNull { - logger.error { "It was not possible to send response to vote." } - }?.also { (messageId) -> - logger.info { "Proxy received confirmation for vote under id: $messageId" } - sendStatsIfAllVoted(token, pollAction.pollId) - } + proxySenderService.send( + token = token, + message = confirmVote( + pollId = pollAction.pollId, + offset = pollAction.optionId, + userId = pollAction.userId + ) + ).whenNull { + logger.error { "It was not possible to send response to vote." } + }?.also { (messageId) -> + logger.info { "Proxy received confirmation for vote under id: $messageId" } + sendStatsIfAllVoted(token, pollAction.pollId) } } @@ -122,7 +113,7 @@ class PollService( val stats = statsFormattingService.formatStats(pollId, conversationMembersCount) .whenNull { logger.warn { "It was not possible to format stats for poll $pollId" } } ?: return - GlobalScope.launch { proxySenderService.send(token, stats) } + proxySenderService.send(token, stats) } /** diff --git a/src/main/kotlin/com/wire/bots/polls/services/ProxySenderService.kt b/src/main/kotlin/com/wire/bots/polls/services/ProxySenderService.kt index 746f0b5..009b984 100644 --- a/src/main/kotlin/com/wire/bots/polls/services/ProxySenderService.kt +++ b/src/main/kotlin/com/wire/bots/polls/services/ProxySenderService.kt @@ -1,6 +1,5 @@ package com.wire.bots.polls.services -import ai.blindspot.ktoolz.extensions.createJson import com.wire.bots.polls.dto.bot.BotMessage import com.wire.bots.polls.dto.roman.Response import com.wire.bots.polls.utils.appendPath @@ -15,6 +14,7 @@ import io.ktor.http.ContentType import io.ktor.http.contentType import io.ktor.http.isSuccess import mu.KLogging +import pw.forst.tools.katlib.createJson import java.nio.charset.Charset /** @@ -32,7 +32,7 @@ class ProxySenderService(private val client: HttpClient, config: ProxyConfigurat * Send given message with provided token. */ suspend fun send(token: String, message: BotMessage): Response? { - logger.debug { "Sending\n:${createJson(message)}" } + logger.debug { "Sending: ${createJson(message)}" } return client.post(body = message) { url(conversationEndpoint) diff --git a/src/main/kotlin/com/wire/bots/polls/services/StatsFormattingService.kt b/src/main/kotlin/com/wire/bots/polls/services/StatsFormattingService.kt index 88c9370..ec83ec0 100644 --- a/src/main/kotlin/com/wire/bots/polls/services/StatsFormattingService.kt +++ b/src/main/kotlin/com/wire/bots/polls/services/StatsFormattingService.kt @@ -1,11 +1,11 @@ package com.wire.bots.polls.services -import ai.blindspot.ktoolz.extensions.newLine -import ai.blindspot.ktoolz.extensions.whenNull import com.wire.bots.polls.dao.PollRepository import com.wire.bots.polls.dto.bot.BotMessage import com.wire.bots.polls.dto.bot.statsMessage import mu.KLogging +import pw.forst.tools.katlib.newLine +import pw.forst.tools.katlib.whenNull class StatsFormattingService( private val repository: PollRepository @@ -39,7 +39,7 @@ class StatsFormattingService( private fun formatVotes(stats: Map, Int>, conversationMembers: Int?): String { // we can use assert as the result size is checked - val maxVotes = stats.values.max()!! + val maxVotes = requireNotNull(stats.values.maxOrNull()) { "There were no stats!" } return stats .map { (option, votingUsers) -> VotingOption(if (votingUsers == maxVotes) "**" else "*", option.second, votingUsers) diff --git a/src/main/kotlin/com/wire/bots/polls/setup/ConfigurationDependencyInjection.kt b/src/main/kotlin/com/wire/bots/polls/setup/ConfigurationDependencyInjection.kt index a564441..2ee5036 100644 --- a/src/main/kotlin/com/wire/bots/polls/setup/ConfigurationDependencyInjection.kt +++ b/src/main/kotlin/com/wire/bots/polls/setup/ConfigurationDependencyInjection.kt @@ -1,7 +1,5 @@ package com.wire.bots.polls.setup -import ai.blindspot.ktoolz.extensions.getEnv -import ai.blindspot.ktoolz.extensions.whenNull import com.wire.bots.polls.dto.conf.DatabaseConfiguration import com.wire.bots.polls.services.ProxyConfiguration import com.wire.bots.polls.setup.EnvConfigVariables.DB_PASSWORD @@ -13,6 +11,8 @@ import com.wire.bots.polls.utils.createLogger import org.kodein.di.Kodein.MainBuilder import org.kodein.di.generic.bind import org.kodein.di.generic.singleton +import pw.forst.tools.katlib.getEnv +import pw.forst.tools.katlib.whenNull import java.io.File private val logger = createLogger("EnvironmentLoaderLogger") diff --git a/src/main/kotlin/com/wire/bots/polls/setup/KtorInstallation.kt b/src/main/kotlin/com/wire/bots/polls/setup/KtorInstallation.kt index 8593383..4b23891 100644 --- a/src/main/kotlin/com/wire/bots/polls/setup/KtorInstallation.kt +++ b/src/main/kotlin/com/wire/bots/polls/setup/KtorInstallation.kt @@ -5,15 +5,20 @@ import com.wire.bots.polls.dao.DatabaseSetup import com.wire.bots.polls.dto.conf.DatabaseConfiguration import com.wire.bots.polls.routing.registerRoutes import com.wire.bots.polls.setup.errors.registerExceptionHandlers +import com.wire.bots.polls.setup.logging.APP_REQUEST +import com.wire.bots.polls.setup.logging.INFRA_REQUEST import com.wire.bots.polls.utils.createLogger import io.ktor.application.Application import io.ktor.application.install +import io.ktor.features.CallId import io.ktor.features.CallLogging import io.ktor.features.ContentNegotiation import io.ktor.features.DefaultHeaders +import io.ktor.features.callId import io.ktor.jackson.jackson import io.ktor.metrics.micrometer.MicrometerMetrics -import io.ktor.request.path +import io.ktor.request.header +import io.ktor.request.uri import io.ktor.routing.routing import io.micrometer.core.instrument.distribution.DistributionStatisticConfig import io.micrometer.prometheus.PrometheusMeterRegistry @@ -23,6 +28,7 @@ import org.kodein.di.generic.instance import org.kodein.di.ktor.kodein import org.slf4j.event.Level import java.text.DateFormat +import java.util.UUID private val installationLogger = createLogger("ApplicationSetup") @@ -70,13 +76,16 @@ fun connectDatabase(k: LazyKodein) { */ fun migrateDatabase(dbConfig: DatabaseConfiguration) { installationLogger.info { "Migrating database." } - val migrationsCount = Flyway + val migrateResult = Flyway .configure() .dataSource(dbConfig.url, dbConfig.userName, dbConfig.password) .load() .migrate() - installationLogger.info { if (migrationsCount == 0) "No migrations necessary." else "Applied $migrationsCount migrations." } + installationLogger.info { + if (migrateResult.migrationsExecuted == 0) "No migrations necessary." + else "Applied ${migrateResult.migrationsExecuted} migrations." + } } /** @@ -92,21 +101,35 @@ fun Application.installFrameworks(k: LazyKodein) { } install(DefaultHeaders) + install(CallLogging) { - level = Level.TRACE - logger = createLogger("EndpointLogger") + // insert nginx id to MDC + mdc(INFRA_REQUEST) { + it.request.header("X-Request-Id") + } + + // use generated call id and insert it to MDC + mdc(APP_REQUEST) { + it.callId + } + + // enable logging just for /messages + // this filter does not influence MDC + filter { + it.request.uri == "/messages" + } + level = Level.DEBUG + logger = createLogger("HttpCallLogger") + } - filter { call -> call.request.path().startsWith("/messages") } + install(CallId) { + generate { + UUID.randomUUID().toString() + } } - configurePrometheus(k) registerExceptionHandlers(k) -} -/** - * Install prometheus. - */ -fun Application.configurePrometheus(k: LazyKodein) { val prometheusRegistry by k.instance() install(MicrometerMetrics) { registry = prometheusRegistry diff --git a/src/main/kotlin/com/wire/bots/polls/setup/logging/JsonLoggingLayout.kt b/src/main/kotlin/com/wire/bots/polls/setup/logging/JsonLoggingLayout.kt new file mode 100644 index 0000000..61ed097 --- /dev/null +++ b/src/main/kotlin/com/wire/bots/polls/setup/logging/JsonLoggingLayout.kt @@ -0,0 +1,59 @@ +package com.wire.bots.polls.setup.logging + + +import ch.qos.logback.classic.spi.ILoggingEvent +import ch.qos.logback.classic.spi.IThrowableProxy +import ch.qos.logback.classic.spi.ThrowableProxyUtil +import ch.qos.logback.core.CoreConstants +import ch.qos.logback.core.LayoutBase +import pw.forst.tools.katlib.createJson +import java.time.Instant +import java.time.ZoneOffset +import java.time.format.DateTimeFormatter + + +/** + * Layout logging into jsons. + */ +class JsonLoggingLayout : LayoutBase() { + + private companion object { + val dateTimeFormatter: DateTimeFormatter = + DateTimeFormatter.ISO_DATE_TIME + .withZone(ZoneOffset.UTC) + } + + override fun doLayout(event: ILoggingEvent): String { + val finalMap: MutableMap = mutableMapOf( + "@timestamp" to formatTime(event), + "message" to event.formattedMessage, + "logger" to event.loggerName, + "level" to event.level.levelStr, + "thread_name" to event.threadName + ) + + finalMap.includeMdc(event, INFRA_REQUEST) + finalMap.includeMdc(event, APP_REQUEST) + finalMap.includeMdc(event, USER_ID) + + // if this was an exception, include necessary data + if (event.throwableProxy != null) { + finalMap["exception"] = exception(event.throwableProxy) + } + + return createJson(finalMap) + CoreConstants.LINE_SEPARATOR + } + + private fun MutableMap.includeMdc(event: ILoggingEvent, mdcKey: String, mapKey: String = mdcKey) { + event.mdcPropertyMap[mdcKey]?.also { mdcValue -> this[mapKey] = mdcValue } + } + + private fun exception(proxy: IThrowableProxy) = mapOf( + "message" to proxy.message, + "class" to proxy.className, + "stacktrace" to ThrowableProxyUtil.asString(proxy) + ) + + private fun formatTime(event: ILoggingEvent): String = + dateTimeFormatter.format(Instant.ofEpochMilli(event.timeStamp)) +} diff --git a/src/main/kotlin/com/wire/bots/polls/setup/logging/MdcConfiguration.kt b/src/main/kotlin/com/wire/bots/polls/setup/logging/MdcConfiguration.kt new file mode 100644 index 0000000..13a3251 --- /dev/null +++ b/src/main/kotlin/com/wire/bots/polls/setup/logging/MdcConfiguration.kt @@ -0,0 +1,16 @@ +package com.wire.bots.polls.setup.logging + +/** + * ID retrieved from the header X-Request-Id coming from the infrastructure nginx. + */ +const val INFRA_REQUEST = "infra_request" + +/** + * ID generated by this application for particular request. + */ +const val APP_REQUEST = "app_request" + +/** + * ID of the user sending message. + */ +const val USER_ID = "user_id" diff --git a/src/main/kotlin/com/wire/bots/polls/utils/Extensions.kt b/src/main/kotlin/com/wire/bots/polls/utils/Extensions.kt index cd9f880..727a721 100644 --- a/src/main/kotlin/com/wire/bots/polls/utils/Extensions.kt +++ b/src/main/kotlin/com/wire/bots/polls/utils/Extensions.kt @@ -1,6 +1,7 @@ package com.wire.bots.polls.utils import mu.KLogging +import org.slf4j.MDC /** * Creates URL from [this] as base and [path] as path @@ -11,3 +12,18 @@ infix fun String.appendPath(path: String) = "${dropLastWhile { it == '/' }}/${pa * Creates logger with given name. */ fun createLogger(name: String) = KLogging().logger("com.wire.$name") + + +/** + * Includes value to current MDC under the key. + */ +inline fun mdc(key: String, value: () -> String?) = mdc(key, value()) + +/** + * Includes value to current MDC under the key if the key is not null. + */ +fun mdc(key: String, value: String?) { + if (value != null) { + MDC.put(key, value) + } +} diff --git a/src/main/resources/logback.xml b/src/main/resources/logback.xml index 4eb4c30..2adb7ba 100644 --- a/src/main/resources/logback.xml +++ b/src/main/resources/logback.xml @@ -1,16 +1,33 @@ - + - %d{dd/MM/yyyy HH:mm:ss} [%level] %logger{36} - %msg%n + %d{dd/MM/yyyy HH:mm:ss} [%level] [%X{mdc-val}] %logger{36} - %msg%n + + + + + + - - - + + + + + + + + + + + + + - + +