Skip to content

Easier configuration of KotlinLoggingConfiguration.logStartupMessage #598

Closed

Description

@josephlbarnett

Per #587, setting KotlinLoggingConfiguration.logStartupMessage allows for not printing out the startup message, as long as it's called prior to any KotlinLogging initialization. Managing that initialization is a little awkward, as at least in my case I've got a bunch of top level private val log...s that get initialized before any call to main().

I've been able to get it to work with a strategically placed run{} block like josephlbarnett/leakycauldron@0622c91 to take care of my main(), but the message shows up still in tests / other entry points, could there be an easier way to get this set throughout a given project?

Activity

  1. github-actions commented on Mar 7, 2026

    @github-actions

    Thank you for reporting an issue. See the wiki for documentation and slack for questions.

  2. oshai commented on Mar 9, 2026

    @oshai
    Owner

    If you're working in jvm only we can add a system property for that in case it's simpler. For Example to configure it when starting the jvm with -Dkotlinlogging.disablestartupmessage.

  3. mymx2 commented on Mar 13, 2026

    @mymx2

    If the default property cannot be set to false, is it possible to use something like an SPI mechanism so that it can be disabled by default at a lower level?

  4. oshai commented on Mar 13, 2026

    @oshai
    Owner

    can you give more details what that means?

  5. mymx2 commented on Mar 13, 2026

    @mymx2

    can you give more details what that means?

    it would be something like:

    spi codes
    package io.github.mymx2.module.core.spi
    
    /**
     * SPI 排除器
     *
     * 用于声明哪些 SPI 实现需要被排除。
     */
    interface ExcludeSPI {
    
      /** @return 需要排除的 SPI 实现类 */
      fun excludes(): Set<Class<*>>
    }
    
    
    package io.github.mymx2.module.core.spi
    
    /**
     * SPI 顺序控制接口
     *
     * 数值越小,优先级越高,越先加载或执行
     */
    interface OrderedSPI {
    
      /** 默认优先级(数值越小 → 优先级越高 → 越先加载或先执行) */
      fun getOrder(): Int = 0
    }
    
    
    package io.github.mymx2.module.core.spi
    
    import java.util.*
    
    /** SPI 加载器 */
    object SpiLoader {
    
      /** 全局排除列表(只加载一次) */
      private val EXCLUDES = loadExcludes()
    
      /** 加载指定 SPI */
      fun <T : Any> load(spiType: Class<T>): List<T> {
        val loader = ServiceLoader.load(spiType)
    
        return loader
          .asSequence()
          .filter { spi -> !isExcluded(spi) }
          .sortedBy { (it as? OrderedSPI)?.getOrder() ?: 0 }
          .toList()
      }
    
      // -------------------------
      // 内部实现
      // -------------------------
    
      private fun loadExcludes(): Set<Class<*>> {
        return ServiceLoader.load(ExcludeSPI::class.java).flatMap { ex -> ex.excludes() }.toSet()
      }
    
      private fun isExcluded(spi: Any): Boolean {
        // ExcludeSPI 本身永远不参与排除
        if (spi is ExcludeSPI) return false
    
        return EXCLUDES.any { excluded -> excluded.isAssignableFrom(spi.javaClass) }
      }
    }
    
    
    interface AppRunners : OrderedSPI {
    
      fun beforeRun()
    
      fun afterRun()
    }
    
    @AutoService(AppRunners::class)
    class DisableKotlinLoggingStartupMessage : AppRunners {
    
      override fun beforeRun() {
        KotlinLoggingConfiguration.logStartupMessage = false
      }
    
      override fun afterRun() {
        // NO-OP
      }
    }
    
  6. oshai commented on Mar 13, 2026

    @oshai
    Owner

    I think there are two KMP-friendly ways we could handle this internally so users don't have to change how they declare their loggers:
    Option 1: Defer the Startup Message Print
    Instead of printing the startup message immediately when the logger factory is initialized, we could delay printing it until the first actual logging call (e.g., the first time log.info() is invoked). This would give main() or test setups plenty of time to disable the message before it actually prints, while having practically zero performance impact if we use a simple thread-safe flag.
    Option 2: expect/actual for Environment Config
    We could introduce an internal expect function to resolve the default configuration value, falling back to environment properties where supported:

    • jvmMain: Check System.getProperty("kotlin-logging.logStartupMessage")
    • nativeMain: Check platform.posix.getenv("KOTLIN_LOGGING_STARTUP_MESSAGE")
    • jsMain / wasmMain: Default to true
      This would allow JVM and Native users to configure the setting globally via their build tools (like Gradle systemProperty) or command-line arguments, solving the test pollution issue entirely.
      I'm open to either approach. Let me know what you think would work best.
  7. mymx2 commented on Mar 14, 2026

    @mymx2

    Lazyinit would be better.

  8. YarnSphere commented on Mar 18, 2026

    @YarnSphere
    Contributor

    Joining this discussion to ask: what's the rationale behind this startup message? Why is it needed and does it need to be opt-out rather than opt-in? I'm using kotlin-logging in a library (often) shipped in browser applications, and I imagine most applications won't want this message to appear in browser console logs, especially in production (during development it would be harmless, I suppose).

    So now I'll probably disable this directly in the library for all consumers, but it feels icky to do so, as it seems to be global configuration which I'd be setting (possibly) for other libraries using kotlin-logging.

    I think this message might be useful when initially trying to integrate kotlin-logging with a logging backend, but honestly I wouldn't expect a logging library to be logging messages by itself, especially by default. Would you consider making this behaviour opt-in instead?

    EDIT: Just found the initial rationale in #584:

    Validation & Diagnostics:

    • Prints the active Logger Factory on initialization (stderr) to aid debugging.

    If the intent is simply to aid in debugging, I'm really not convinced that this should be enabled by default.

  9. Zordid commented on Apr 13, 2026

    @Zordid

    Also joining this discussion: I just saw this startup message for the first time - and immediately went to look for how to disable it. Why was this even added? To me, this is just noise I don't care about and now I have to actively do "something" to get back to how it was before. Why?

  10. added a commit that references this issue on May 19, 2026
    3e6096d
  11. oshai commented on May 21, 2026

    @oshai
    Owner

    Rationale is explained here: #602 (comment)

    I want the lib not to hide errors for first time users.

    Hope that makes some sense and the provided silution helps.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions