A tiny Kotlin API for cheap logging on top of Android's normal Log class.

Overview

Square Logcat

logcat { "I CAN HAZ LOGZ?" }

A tiny Kotlin API for cheap logging on top of Android's normal Log class.

Table of contents

logo_512.png

This fantastic logo is brought to you by @rjrjr.

Setup

Add the logcat dependency to your library or app's build.gradle file:

dependencies {
  implementation 'com.squareup.logcat:logcat:0.1'
}

Install AndroidLogcatLogger in Application.onCreate():

import android.app.Application
import logcat.AndroidLogcatLogger
import logcat.LogPriority.VERBOSE

class ExampleApplication : Application() {
  override fun onCreate() {
    super.onCreate()
    // Log all priorities in debug builds, no-op in release builds.
    AndroidLogcatLogger.installOnDebuggableApp(this, minPriority = VERBOSE)
  }
}

Usage

The logcat() function has 3 parameters: an optional priority, an optional tag, and a required string producing lambda. The lambda is only evaluated if a logger is installed and the logger deems the priority loggable.

The priority defaults to LogPriority.DEBUG.

The tag defaults to the class name of the log call site, without any extra runtime cost. This works because logcat() is an inlined extension function of Any and has access to this from which it can extract the class name. If logging from a standalone function which has no this, use the logcat overload which requires a tag parameter.

The logcat() function does not take a Throwable parameter. Instead, the library provides a Throwable extension function: Throwable.asLog() which returns a loggable string.

import logcat.LogPriority.INFO
import logcat.asLog
import logcat.logcat

class MouseController {

  fun play() {
    val state = "CHEEZBURGER"
    logcat { "I CAN HAZ $state?" }
    // logcat output: D/MouseController: I CAN HAZ CHEEZBURGER?

    logcat(INFO) { "DID U ASK 4 MOAR INFO?" }
    // logcat output: I/MouseController: DID U ASK 4 MOAR INFO?

    logcat { exception.asLog() }
    // logcat output: D/MouseController: java.lang.RuntimeException: FYLEZ KERUPTED
    //                        at sample.MouseController.play(MouseController.kt:22)
    //                        ...

    logcat("Lolcat") { "OH HI" }
    // logcat output: D/Lolcat: OH HI
  }
}

Motivations

We built this small library to fit the specific needs of the Square Point of Sale application. We used Timber heavily before that, and love the simplicity of its API and the ability of its DebugTree to automatically figure out from which class it's being called from and use that class name as its tag. Here are our motivations for replacing it with logcat() in the Square Point of Sale:

  • Kotlin support for string interpolation is really nice. We love to use that for logs! Unfortunately that can be costly and a waste of good CPU if logging is disabled anyway. By using an inlined string producing lambda, logcat() supports string interpolation without any performance cost when logging is disabled.
  • Timber's DebugTree captures the calling class name as a tag by creating a stacktrace, which can be expensive. By making logcat() an extension function of Any, we can call this::class.java and get the calling context without creating a stacktrace.
  • The current implementation uses the outer most simple class name as the tag, i.e. the string between on the last . and the first $. That might not always be what you want. Also, when logging from an abstract class the tag will be the name of the subclass at runtime. We've found these limitations to be totally fine with us so far.
  • Most of the time, our developers just want to "send something to logcat" without even thinking about priority. logcat() picks "debug" as the right default to provide more consistency across a large codebase. Making the priority a parameter also means only one method to learn, and you don't have to learn / think about priorities prior to writing a log. This becomes especially important when there are several parameters requiring overloads (e.g. in Timber (6 priorities + 1 generic log method) * 3 overloads = 21 methods to choose from).
  • The lack of throwable parameter is also intentional. It just creates more overloads and confusion (e.g. "what's the param order?"), when really logs are about strings and all you need is an easy way to turn a throwable into a loggable string. Hence Throwable.asLog().
  • The name logcat() is intentionally boring and identical to the Android command line tool. This makes it easy to remember and developers know exactly what this does, i.e. log to the local device. One could setup a custom logger that send logs remotely in release builds, however we do not recommend doing so: in our experience, remote logs should be distinct in code from local logs and clearly identified as such, because the volume and performance impact should be very distinct.
  • The API for installing a logger is separated out from the API to log, as these operations occur in very distinct contexts.

License

Copyright 2021 Square Inc.

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.
Comments
  • Update setup-java action to v2

    Update setup-java action to v2

    Updating the setup-java action to v2.

    • V2 supports custom distributions and provides support for Zulu OpenJDK, Eclipse Temurin and Adopt OpenJDK. V1 supports only Zulu OpenJDK.
    • V1 supported legacy Java syntax such as 1.8 (same as 8) and 1.8.0.212 (same as 8.0.212). V2 dropped support for legacy syntax.
    opened by nuhkoca 1
  • Avoid usage of low-level logging call Log.println?

    Avoid usage of low-level logging call Log.println?

    If the Log level is != ASSERT the library uses the low-level logging method Log.println(priority, tag, part).

    I know that this part is borrowed from Timber, but I wonder what the benefit of this is, over using the corresponding higher level log methods (Log.v, Log.d ...)? Because from my understanding (have not tested it) this will prevent R8 from removing the logging calls with this recommended and commonly used proguard rule:

    -assumenosideeffects class android.util.Log {
        public static boolean isLoggable(java.lang.String, int);
        public static int v(...);
        public static int i(...);
        public static int w(...);
        public static int d(...);
        public static int e(...);
    }
    

    I would suggest to change the logToLogcat function to this:

    private fun logToLogcat(
      priority: LogPriority,
      tag: String,
      part: String
      ) {
        when (priority) {
          LogPriority.VERBOSE -> Log.v(tag, part)
          LogPriority.DEBUG -> Log.d(tag, part)
          LogPriority.INFO -> Log.i(tag, part)
          LogPriority.WARN -> Log.w(tag, part)
          LogPriority.ERROR -> Log.e(tag, part)
          LogPriority.ASSERT -> Log.wtf(tag, part)
        }
    }
    

    Any opinions?

    opened by G00fY2 0
  • Improve the story of using this from inside composable functions

    Improve the story of using this from inside composable functions

    Currently, when inside a top level function (ofter true for composable funs) the api forces you to pass a tag manually, sort of killing the simplicity of "I just want to log something here" this library usually provides. With that said, as far as I am aware there is no way to simply by default take the function name as the tag or something similar, so maybe this isn't a solvable problem and we simply have to pass a tag ourselves in such cases. If that's the case feel free to simply close this issue.

    opened by StylianosGakis 0
  • Initial KMP Restructure

    Initial KMP Restructure

    • Updated src into source sets for common/jvm/js/android/native
    • Moved JVM code to JVM source set
    • Extracted platform dependent pieces into expect/actual
    • Implemented required 'actual's for JS & Native
    • Moved AndroidLogcatLogger to android source set
    opened by frenziedherring 3
  • Log tag issue in coroutine blocks

    Log tag issue in coroutine blocks

    I call a logcat function with default parameters in my kotlin coroutine block like viewModelScope.launch {}, but the tag name seems get from the nested class not from the root class (Eg. StandaloneCoroutine: xxxx). Should we make the tag name more generally or something just like Timber is doing?

    opened by jackvt93 1
Releases(v0.1)
Owner
Square
Square
An easy way to customize your log in Android´╝îincluding output to console, writing log to file in high performance way and so on

EasyLog An easy way to customize your log in Android´╝îincluding output to console, writing log to file in high performance way and so on. 1. Initializa

Taylor 40 Dec 8, 2022
Kermit is a Kotlin Multiplatform logging utility with composable log outputs

Kermit is a Kotlin Multiplatform logging utility with composable log outputs. The library provides prebuilt loggers for outputting to platform logging tools such as Logcat and NSLog.

Touchlab 395 Jan 4, 2023
Kotlin multi-platform logging library with structured logging and coroutines support

Klogging Klogging is a pure-Kotlin logging library that aims to be flexible and easy to use. It uses Kotlin idioms for creating loggers and sending lo

Klogging 51 Dec 20, 2022
This is an Kotlin Library that enables Annotation-triggered method call logging for Kotlin Multiplatform.

This is an Kotlin Library that enables Annotation-triggered method call logging for Kotlin Multiplatform.

Jens Klingenberg 187 Dec 18, 2022
simple Kotlin logging: colorized logs for Kotlin on the JVM

sklog - simple Kotlin logging Kotlin (JVM) logging library for printing colorized text to the console, with an easy upgrade path to the popular kotlin

null 1 Jul 26, 2022
Simple application to log your mood through the day and explain feature flags.

Mood Logger App (Android version) This Repo This repository contains code for building a very basic application to log your mood through the days. The

MongoDB Developer Relations 3 Oct 24, 2021
Library that makes debugging, log collection, filtering and analysis easier.

AndroidLogger Android Library that makes debugging, log collection, filtering and analysis easier. Contains 2 modules: Logger: 'com.github.ShiftHackZ.

ShiftHackZ 2 Jul 13, 2022
A demonstration of Kotlin-logging with logback.

try-kotlin-logging A demonstration of Kotlin-logging with logback. Usage # output a log to STDOUT and file(myApp.log) $ ./gradlew run # => 2021-12-11

Hayato Tachikawa 1 Dec 13, 2021
Annotation-triggered method call logging for your debug builds.

Hugo Annotation-triggered method call logging for your debug builds. As a programmer, you often add log statements to print method calls, their argume

Jake Wharton 7.9k Dec 31, 2022
­čôäThe reliable, generic, fast and flexible logging framework for Android

logback-android v2.0.0 Overview logback-android brings the power of logback to Android. This library provides a highly configurable logging framework

Tony Trinh 1.1k Jan 5, 2023
An in-display logging library for Android ­čô▓

Vlog provides an easy and convenient way to access logs right on your phone.

girish budhwani 121 Dec 26, 2022
Jambo is an open source remote logging library

Jambo Jambo is an open source remote logging library. For those who would like to see their logs remotely on their android device Jambo is the library

Tabasumu 6 Aug 26, 2022
Napier is a logger library for Kotlin Multiplatform.

Napier is a logger library for Kotlin Multiplatform. It supports for the android, ios, jvm, js. Logs written in common module are displayed on logger

Akira Aratani 457 Jan 7, 2023
Kotlin Multi Platform Logger, for android an ios : Logcat & print

Multiplatform Preferences Use a single object : Logger in your kotlin shared projects to display logs Note you can also use it in your real code on An

Florent CHAMPIGNY 49 Aug 22, 2022
Yakl - Yet Another Kotlin Logger

YAKL Yet Another Kotlin Logger. Motivation Current jvm loggers have some disadva

Mark Kosichkin 4 Jan 19, 2022
A logger with a small, extensible API which provides utility on top of Android's normal Log class.

This is a logger with a small, extensible API which provides utility on top of Android's normal Log class. I copy this class into all the little apps

Jake Wharton 9.9k Jan 8, 2023
A logger with a small, extensible API which provides utility on top of Android's normal Log class.

This is a logger with a small, extensible API which provides utility on top of Android's normal Log class. I copy this class into all the little apps

Jake Wharton 9.8k Dec 30, 2022
A tiny window overlay to log app internal on top of your android app

DebugOverlay A logcat alike overlay to display log messages in your app as independent overlay. Typically in android you would log some app internals

Hannes Dorfmann 150 Nov 29, 2022
Annotation Processing Library. Generates proxy class on top of interface/abstract class, that allows to intercept calls. Also known as a design pattern: proxy, delegate, interceptor.

1. AutoProxy Annotation Processing Library. Generates proxy class on top of interface/abstract class, that allows to intercept calls. Also known as a

Oleksandr 19 Nov 24, 2022
An easy way to customize your log in Android´╝îincluding output to console, writing log to file in high performance way and so on

EasyLog An easy way to customize your log in Android´╝îincluding output to console, writing log to file in high performance way and so on. 1. Initializa

Taylor 40 Dec 8, 2022