SubwayTooter-Android-App/anko/src/main/java/org/jetbrains/anko/Logging.kt

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)
}
}