278 lines
9.0 KiB
Kotlin
278 lines
9.0 KiB
Kotlin
/*
|
|
* Copyright 2016 JetBrains s.r.o.
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
@file:Suppress("unused", "NOTHING_TO_INLINE", "MatchingDeclarationName", "NAME_SHADOWING")
|
|
@file:JvmName("Logging")
|
|
|
|
package org.jetbrains.anko
|
|
|
|
import android.util.Log
|
|
|
|
/**
|
|
* Interface for the Anko logger.
|
|
* Normally you should pass the logger tag to the [Log] methods, such as [Log.d] or [Log.e].
|
|
* This can be inconvenient because you should store the tag somewhere or hardcode it,
|
|
* which is considered to be a bad practice.
|
|
*
|
|
* Instead of hardcoding tags, Anko provides an [AnkoLogger] interface. You can just add the interface to
|
|
* any of your classes, and use any of the provided extension functions, such as
|
|
* [AnkoLogger.debug] or [AnkoLogger.error].
|
|
*
|
|
* The tag is the simple class name by default, but you can change it to anything you want just
|
|
* by overriding the [loggerTag] property.
|
|
*/
|
|
interface AnkoLogger {
|
|
/**
|
|
* The logger tag used in extension functions for the [AnkoLogger].
|
|
* Note that the tag length should not be more than 23 symbols.
|
|
*/
|
|
val loggerTag: String
|
|
get() = getTag(javaClass)
|
|
}
|
|
|
|
fun AnkoLogger(clazz: Class<*>): AnkoLogger = object : AnkoLogger {
|
|
override val loggerTag = getTag(clazz)
|
|
}
|
|
|
|
fun AnkoLogger(tag: String): AnkoLogger = object : AnkoLogger {
|
|
init {
|
|
assert(tag.length <= 23) { "The maximum tag length is 23, got $tag" }
|
|
}
|
|
|
|
override val loggerTag = tag
|
|
}
|
|
|
|
inline fun <reified T : Any> AnkoLogger(): AnkoLogger = AnkoLogger(T::class.java)
|
|
|
|
/**
|
|
* Send a log message with the [Log.VERBOSE] severity.
|
|
* Note that the log message will not be written if the current log level is above [Log.VERBOSE].
|
|
* The default log level is [Log.INFO].
|
|
*
|
|
* @param message the message text to log. `null` value will be represent as "null", for any other value
|
|
* the [Any.toString] will be invoked.
|
|
* @param thr an exception to log (optional).
|
|
*
|
|
* @see [Log.v].
|
|
*/
|
|
fun AnkoLogger.verbose(message: Any?, thr: Throwable? = null) {
|
|
log(this, message, thr, Log.VERBOSE,
|
|
{ tag, msg -> Log.v(tag, msg) },
|
|
{ tag, msg, thr -> Log.v(tag, msg, thr) })
|
|
}
|
|
|
|
/**
|
|
* Send a log message with the [Log.DEBUG] severity.
|
|
* Note that the log message will not be written if the current log level is above [Log.DEBUG].
|
|
* The default log level is [Log.INFO].
|
|
*
|
|
* @param message the message text to log. `null` value will be represent as "null", for any other value
|
|
* the [Any.toString] will be invoked.
|
|
* @param thr an exception to log (optional).
|
|
*
|
|
* @see [Log.d].
|
|
*/
|
|
fun AnkoLogger.debug(message: Any?, thr: Throwable? = null) {
|
|
log(this, message, thr, Log.DEBUG,
|
|
{ tag, msg -> Log.d(tag, msg) },
|
|
{ tag, msg, thr -> Log.d(tag, msg, thr) })
|
|
}
|
|
|
|
/**
|
|
* Send a log message with the [Log.INFO] severity.
|
|
* Note that the log message will not be written if the current log level is above [Log.INFO]
|
|
* (it is the default level).
|
|
*
|
|
* @param message the message text to log. `null` value will be represent as "null", for any other value
|
|
* the [Any.toString] will be invoked.
|
|
* @param thr an exception to log (optional).
|
|
*
|
|
* @see [Log.i].
|
|
*/
|
|
fun AnkoLogger.info(message: Any?, thr: Throwable? = null) {
|
|
log(this, message, thr, Log.INFO,
|
|
{ tag, msg -> Log.i(tag, msg) },
|
|
{ tag, msg, thr -> Log.i(tag, msg, thr) })
|
|
}
|
|
|
|
/**
|
|
* Send a log message with the [Log.WARN] severity.
|
|
* Note that the log message will not be written if the current log level is above [Log.WARN].
|
|
* The default log level is [Log.INFO].
|
|
*
|
|
* @param message the message text to log. `null` value will be represent as "null", for any other value
|
|
* the [Any.toString] will be invoked.
|
|
* @param thr an exception to log (optional).
|
|
*
|
|
* @see [Log.w].
|
|
*/
|
|
fun AnkoLogger.warn(message: Any?, thr: Throwable? = null) {
|
|
log(this, message, thr, Log.WARN,
|
|
{ tag, msg -> Log.w(tag, msg) },
|
|
{ tag, msg, thr -> Log.w(tag, msg, thr) })
|
|
}
|
|
|
|
/**
|
|
* Send a log message with the [Log.ERROR] severity.
|
|
* Note that the log message will not be written if the current log level is above [Log.ERROR].
|
|
* The default log level is [Log.INFO].
|
|
*
|
|
* @param message the message text to log. `null` value will be represent as "null", for any other value
|
|
* the [Any.toString] will be invoked.
|
|
* @param thr an exception to log (optional).
|
|
*
|
|
* @see [Log.e].
|
|
*/
|
|
fun AnkoLogger.error(message: Any?, thr: Throwable? = null) {
|
|
log(this, message, thr, Log.ERROR,
|
|
{ tag, msg -> Log.e(tag, msg) },
|
|
{ tag, msg, thr -> Log.e(tag, msg, thr) })
|
|
}
|
|
|
|
/**
|
|
* Send a log message with the "What a Terrible Failure" severity.
|
|
* Report an exception that should never happen.
|
|
*
|
|
* @param message the message text to log. `null` value will be represent as "null", for any other value
|
|
* the [Any.toString] will be invoked.
|
|
* @param thr an exception to log (optional).
|
|
*
|
|
* @see [Log.wtf].
|
|
*/
|
|
fun AnkoLogger.wtf(message: Any?, thr: Throwable? = null) {
|
|
if (thr != null) {
|
|
Log.wtf(loggerTag, message?.toString() ?: "null", thr)
|
|
} else {
|
|
Log.wtf(loggerTag, message?.toString() ?: "null")
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Send a log message with the [Log.VERBOSE] severity.
|
|
* Note that the log message will not be written if the current log level is above [Log.VERBOSE].
|
|
* The default log level is [Log.INFO].
|
|
*
|
|
* @param message the function that returns message text to log.
|
|
* `null` value will be represent as "null", for any other value the [Any.toString] will be invoked.
|
|
*
|
|
* @see [Log.v].
|
|
*/
|
|
inline fun AnkoLogger.verbose(message: () -> Any?) {
|
|
val tag = loggerTag
|
|
if (Log.isLoggable(tag, Log.VERBOSE)) {
|
|
Log.v(tag, message()?.toString() ?: "null")
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Send a log message with the [Log.DEBUG] severity.
|
|
* Note that the log message will not be written if the current log level is above [Log.DEBUG].
|
|
* The default log level is [Log.INFO].
|
|
*
|
|
* @param message the function that returns message text to log.
|
|
* `null` value will be represent as "null", for any other value the [Any.toString] will be invoked.
|
|
*
|
|
* @see [Log.d].
|
|
*/
|
|
inline fun AnkoLogger.debug(message: () -> Any?) {
|
|
val tag = loggerTag
|
|
if (Log.isLoggable(tag, Log.DEBUG)) {
|
|
Log.d(tag, message()?.toString() ?: "null")
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Send a log message with the [Log.INFO] severity.
|
|
* Note that the log message will not be written if the current log level is above [Log.INFO].
|
|
* The default log level is [Log.INFO].
|
|
*
|
|
* @param message the function that returns message text to log.
|
|
* `null` value will be represent as "null", for any other value the [Any.toString] will be invoked.
|
|
*
|
|
* @see [Log.i].
|
|
*/
|
|
inline fun AnkoLogger.info(message: () -> Any?) {
|
|
val tag = loggerTag
|
|
if (Log.isLoggable(tag, Log.INFO)) {
|
|
Log.i(tag, message()?.toString() ?: "null")
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Send a log message with the [Log.WARN] severity.
|
|
* Note that the log message will not be written if the current log level is above [Log.WARN].
|
|
* The default log level is [Log.INFO].
|
|
*
|
|
* @param message the function that returns message text to log.
|
|
* `null` value will be represent as "null", for any other value the [Any.toString] will be invoked.
|
|
*
|
|
* @see [Log.w].
|
|
*/
|
|
inline fun AnkoLogger.warn(message: () -> Any?) {
|
|
val tag = loggerTag
|
|
if (Log.isLoggable(tag, Log.WARN)) {
|
|
Log.w(tag, message()?.toString() ?: "null")
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Send a log message with the [Log.ERROR] severity.
|
|
* Note that the log message will not be written if the current log level is above [Log.ERROR].
|
|
* The default log level is [Log.INFO].
|
|
*
|
|
* @param message the function that returns message text to log.
|
|
* `null` value will be represent as "null", for any other value the [Any.toString] will be invoked.
|
|
*
|
|
* @see [Log.e].
|
|
*/
|
|
inline fun AnkoLogger.error(message: () -> Any?) {
|
|
val tag = loggerTag
|
|
if (Log.isLoggable(tag, Log.ERROR)) {
|
|
Log.e(tag, message()?.toString() ?: "null")
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Return the stack trace [String] of a throwable.
|
|
*/
|
|
inline fun Throwable.getStackTraceString(): String = Log.getStackTraceString(this)
|
|
|
|
private inline fun log(
|
|
logger: AnkoLogger,
|
|
message: Any?,
|
|
thr: Throwable?,
|
|
level: Int,
|
|
f: (String, String) -> Unit,
|
|
fThrowable: (String, String, Throwable) -> Unit,
|
|
) {
|
|
val tag = logger.loggerTag
|
|
if (Log.isLoggable(tag, level)) {
|
|
if (thr != null) {
|
|
fThrowable(tag, message?.toString() ?: "null", thr)
|
|
} else {
|
|
f(tag, message?.toString() ?: "null")
|
|
}
|
|
}
|
|
}
|
|
|
|
private fun getTag(clazz: Class<*>): String {
|
|
val tag = clazz.simpleName
|
|
return if (tag.length <= 23) {
|
|
tag
|
|
} else {
|
|
tag.substring(0, 23)
|
|
}
|
|
} |