LoginSignup
1

More than 5 years have passed since last update.

ラムダが使えるLoggerを自作してみた

Posted at

ラムダを使用して、ログレベルを超えない場合は評価しないロガーを作ってみた。

  • ログメッセージ自体の生成にCPUを使うようなことはないと思うが、ネックになりうるなら有用かもしれない。
  • inline fun だからラムダのオーバーヘッドがないはず。
  • 正直Timberとかそこら辺のライブラリ使ったほうがいいと思う。
Logger.kt
/**
 * ラムダを使用したロガー
 *
 * 使用例
 * ```
 * class MyApplication : Application() {
 *     override fun onCreate() {
 *         Logger.initialize(if (BuildConfig.DEBUG) Log.VERBOSE else Log.ERROR, AndroidLogFactory())
 *     }
 * }
 * 
 * class MyFragment : Fragment() {
 *     private val logger = Logger("MyFragment")
 *
 *     fun doSomething() {
 *         logger.v { "foo bar baz" }
 *         logger.e({ "error" }, RuntimeException())
 *     }
 * }
 * ```
 */
class Logger(val tag: String) {

    companion object {
        var priority: Int = Log.VERBOSE
            private set
        var logFactory: LogFactory = SystemLogFactory()
            private set

        fun initialize(priority: Int, logFactory: LogFactory) {
            this.priority = priority
            this.logFactory = logFactory
        }
    }

    inline fun log(priority: Int, msgCreator: () -> String, error: Throwable?) {
        if (priority < Companion.priority) return
        factory.log(priority, tag, msgCreator(), error)
    }

    inline fun v(msgCreator: () -> String) = log(android.util.Log.VERBOSE, msgCreator, null)
    inline fun v(msgCreator: () -> String, error: Throwable) = log(android.util.Log.VERBOSE, msgCreator, error)
    inline fun d(msgCreator: () -> String) = log(android.util.Log.DEBUG, msgCreator, null)
    inline fun d(msgCreator: () -> String, error: Throwable) = log(android.util.Log.DEBUG, msgCreator, error)
    inline fun i(msgCreator: () -> String) = log(android.util.Log.INFO, msgCreator, null)
    inline fun i(msgCreator: () -> String, error: Throwable) = log(android.util.Log.INFO, msgCreator, error)
    inline fun w(msgCreator: () -> String) = log(android.util.Log.WARN, msgCreator, null)
    inline fun w(msgCreator: () -> String, error: Throwable) = log(android.util.Log.WARN, msgCreator, error)
    inline fun e(msgCreator: () -> String) = log(android.util.Log.ERROR, msgCreator, null)
    inline fun e(msgCreator: () -> String, error: Throwable) = log(android.util.Log.ERROR, msgCreator, error)
    inline fun wtf(msgCreator: () -> String) = log(android.util.Log.ASSERT, msgCreator, null)
    inline fun wtf(msgCreator: () -> String, error: Throwable) = log(android.util.Log.ASSERT, msgCreator, error)

    interface LogFactory {
        fun log(priority: Int, tag: String, msg: String, error: Throwable?)
    }

    class SystemLogFactory : LogFactory {
        override fun log(priority: Int, tag: String, msg: String, error: Throwable?) {
            System.out.println("${priority.label}/$tag: $msg")
            error?.printStackTrace(System.err)
        }

        private val Int.label: String get() = when (this) {
            android.util.Log.VERBOSE -> "V"
            android.util.Log.DEBUG -> "D"
            android.util.Log.INFO -> "I"
            android.util.Log.WARN -> "W"
            android.util.Log.ERROR -> "E"
            android.util.Log.ASSERT -> "WTF"
            else -> throw IllegalArgumentException("$this is unknown priority.")
        }
    }
}
AndroidLogFactory
/**
 * [Log]を使用するログファクトリー
 * テストコードでのクラッシュを避けるために実装
 */
class AndroidLogFactory : Logger.LogFactory {
    override fun log(priority: Int, tag: String, msg: String, error: Throwable?) {
        val errorMessage = error?.let { "\n" + Log.getStackTraceString(it) } ?: ""
        Log.println(priority, tag, msg + errorMessage)
    }
}

KDocにあるように、JVMテスト時に android.util.Log のメソッドコールによるクラッシュを避けたかったのが主な目的。

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1