{"id":28461687,"url":"https://github.com/diamondedge1/kmlogging","last_synced_at":"2025-07-03T08:30:56.281Z","repository":{"id":37571027,"uuid":"332284926","full_name":"DiamondEdge1/KmLogging","owner":"DiamondEdge1","description":"Kotlin multiplatform logging. High performance, composable and simple to use.","archived":false,"fork":false,"pushed_at":"2025-03-25T19:10:25.000Z","size":360,"stargazers_count":109,"open_issues_count":0,"forks_count":14,"subscribers_count":3,"default_branch":"main","last_synced_at":"2025-06-07T04:07:01.351Z","etag":null,"topics":["android","jvm","kotlin","kotlin-multiplatform","logger","logging","logging-library","multiplatform-kotlin-library","wasm","wasmjs"],"latest_commit_sha":null,"homepage":"","language":"Kotlin","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/DiamondEdge1.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2021-01-23T18:52:16.000Z","updated_at":"2025-05-29T06:23:10.000Z","dependencies_parsed_at":"2024-01-16T15:40:44.756Z","dependency_job_id":"17e02e65-7459-483a-8491-4cea6a18476e","html_url":"https://github.com/DiamondEdge1/KmLogging","commit_stats":null,"previous_names":["diamondedge1/kmlogging","lighthousegames/kmlogging"],"tags_count":8,"template":false,"template_full_name":null,"purl":"pkg:github/DiamondEdge1/KmLogging","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/DiamondEdge1%2FKmLogging","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/DiamondEdge1%2FKmLogging/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/DiamondEdge1%2FKmLogging/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/DiamondEdge1%2FKmLogging/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/DiamondEdge1","download_url":"https://codeload.github.com/DiamondEdge1/KmLogging/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/DiamondEdge1%2FKmLogging/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":263290283,"owners_count":23443565,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["android","jvm","kotlin","kotlin-multiplatform","logger","logging","logging-library","multiplatform-kotlin-library","wasm","wasmjs"],"created_at":"2025-06-07T04:06:57.983Z","updated_at":"2025-07-03T08:30:56.271Z","avatar_url":"https://github.com/DiamondEdge1.png","language":"Kotlin","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Kotlin Multiplatform Logging  \u003cimg src=\"https://upload.wikimedia.org/wikipedia/commons/0/06/Kotlin_Icon.svg\" width=\"30\"\u003e  \u003cimg src=\"https://upload.wikimedia.org/wikipedia/commons/d/d7/Android_robot.svg\" width=\"30\"\u003e  \u003cimg src=\"https://upload.wikimedia.org/wikipedia/commons/6/66/Apple_iOS_logo.svg\" width=\"30\"\u003e  \u003cimg src=\"https://upload.wikimedia.org/wikipedia/commons/6/6a/JavaScript-logo.png\" width=\"30\"\u003e  \u003cimg src=\"https://upload.wikimedia.org/wikipedia/commons/1/18/OpenJDK_logo.svg\" width=\"80\"\u003e\n\n[![ver](https://img.shields.io/maven-central/v/com.diamondedge/logging)](https://repo1.maven.org/maven2/com/diamondedge/logging/)\n[![Kotlin](https://img.shields.io/badge/Kotlin-2.0.21-blue.svg?logo=kotlin)](http://kotlinlang.org)\n![kmm](https://img.shields.io/badge/Multiplatform-Android%20iOS%20WasmJS%20JS%20JVM-blue)\n[![License](https://img.shields.io/badge/License-Apache--2.0-blue)](http://www.apache.org/licenses/LICENSE-2.0)\n[![libs.tech recommends](https://libs.tech/project/332284926/badge.svg)](https://libs.tech/project/332284926/kmlogging)\n\nKotlin multiplatform logging library targeting Android, iOS, JVM, WasmJS and JS.\n\n## Features\n\n* Uses the native logging facility on each platform: Log on Android, os_log on iOS, SLF4J on JVM and\n  console on WasmJs and JavaScript.\n* High performance. Very little overhead when logging is disabled. When disabled, only one boolean\n  is evaluated and no function calls. Building the message string and running the code to calculate\n  it is not executed.\n* No configuration necessary.\n* Can add additional loggers such as Crashlytics or replace/extend the builtin PlatformLogger with\n  something else\n* Can provide custom/configurable log level control on builtin PlatformLogger such as changing the\n  log level from Remote Config\n* Each logger can log at a different level.\n* All platforms can use the same set of loggers by configuring in common code or can use different\n  ones on each platform by configuring in platform specific code.\n* It is thread-safe\n\n## Migration from version 1.x\n\nVersion 2.0 changed the package from `org.lighthousegames.logging` to `com.diamondedge.logging`\nTo do the migration simply change the dependency to\n`implementation(\"com.diamondedge:logging:$logging_version\")`\nand replace all occurrences of `org.lighthousegames.logging` in your code base with\n`com.diamondedge.logging`.\n\n## Setup\n\nThe library is available from the Maven Central repository with the current version\nof ![ver](https://img.shields.io/maven-central/v/com.diamondedge/logging)\nYou should use version `2.0.21` or later of the kotlin multiplatform plugin (Older version of Kotlin\nare supported in older versions of the library). Place the following in the commonMain section.\n\nbuild.gradle.kts\n\n```kotlin\nsourceSets {\n    val commonMain by getting {\n        dependencies {\n            api(\"com.diamondedge:logging:$logging_version\")\n        }\n    }\n}\n```\n\nbuild.gradle\n\n```gradle\nsourceSets {\n    commonMain {\n        dependencies {\n            api \"com.diamondedge:logging:$logging_version\"\n        }\n    }\n}\n```\n\n## Setup for non-multiplatform\n\nSo, you want the best and easiest to use kotlin logging library but are not yet ready for\nmultiplatform development then just include on the following in your `dependencies` section:\n\n```gradle\n    implementation(\"com.diamondedge:logging-android:$logging_version\")\n    implementation(\"com.diamondedge:logging-jvm:$logging_version\")\n    implementation(\"com.diamondedge:logging-js:$logging_version\")\n```\n\n## Usage\n\nCreate an instance of logging class by using the convenience function `logging()`.\nOn Android, iOS and JVM the class from where `logging()` was called will be used as the tag in the\nlogs. For JS or when a specific tag is desired it can be supplied i.e `val log = logging(\"mytag\")`\nor `val log = KmLog(\"mytag\")`\n\n```kotlin\nclass MyClass {\n    fun easyPeasy() {\n        log.i { \"use traditional Android short function name\" }\n    }\n\n    fun easyPeasyLemonSqueesy() {\n        log.info { \"use longer more explicit function name\" }\n    }\n\n    companion object {\n        val log = logging()\n    }\n}\n```\n\n## Performance\n\nThere are 3 aspects to logging that have significant overhead:\n\n1. calculating the tag or class name\n1. formatting the log message\n1. determining whether a given log call should be logged or not\n\nKmLogging addresses and improves on each of these as compared to other logging libraries:\n\n1. KmLogging calculates the tag just once per module The tag (class name) is only when\n   the `val log = logging()` is executed. Most logging libraries calculate it on every log call or\n   require you to supply it. Calculating the tag is expensive since it normally requires creating\n   and parsing a call stack to get the class name. KmLogging chose to eliminate this performance\n   drain by asking the developer to add an additional line of code `val log = logging()` to each\n   class or module so this cost is only paid one time per class.\n1. KmLogging does not evaluate the message string except when it will be output. Formatting the log\n   message can require many steps and the concatenation of the strings is expensive. All of this\n   code is captured in a lambda which is not executed unless it is determined that the result will\n   be output to the logs.\n1. KmLogging has one a single boolean check to determine if it should log. Calculating whether each\n   level is to be logged is calculated at configuration time i.e. only once and then a boolean flag\n   is stored for each level to signify whether that level is logging or not. The logging functions\n   are inline and result in evaluating one boolean to determine if any logging work should be done.\n   Most logging libraries have a lot of overhead such as many method calls and loops over the\n   configuration objects to determine if logging should be performed or not.\n\nSince KmLogging has very little overhead when it is disabled, if you turn off logging in release\nbuilds you can leave a lot of logging in your code without paying performance penalties in\nproduction.\n\nNote: if any logger has a given log level enabled then the lambda for that log level will be\nevaluated. Suppose you used the default configuration and you added a Crashlytics logger that logs\nat info, warn and error levels. This would mean that the lambda for info, warn and error levels will\nbe evaluated because the Crashlytics logger needs it. So in this scenario you would want to have\nminimal info logging code so as to not slow down the application at runtime and put most of the\nlogging at verbose and debug levels where it will not be evaluated in release builds.\n\n## Configuration\n\nWith no configuration, logging is enabled for all log levels.\n\n### Turn off logging for release builds\n\nIf logging is not desired for release builds then use the following to turn off the logging of the\ndefault PlatformLogger\n\n```kotlin\nKmLogging.setLogLevel(LogLevel.Off)\n\n// in Android this could be based on the debug flag:\nKmLogging.setLogLevel(if (BuildConfig.DEBUG) LogLevel.Verbose else LogLevel.Off)\n```\n\nor use `PlatformLogger` and supply it a log level controller that is disabled for all log levels:\n\n```kotlin\nKmLogging.setLoggers(PlatformLogger(FixedLogLevel(false)))\n\n// in Android this could be based on the debug flag:\nKmLogging.setLoggers(PlatformLogger(FixedLogLevel(BuildConfig.DEBUG)))\n```\n\n## Kotlin version support\n\n| KmLogging version | Kotlin version |\n|-------------------|----------------|\n| 2.0.3             | 2.0.21         |\n| 1.5.0             | 1.9.24         |\n| 1.4.2             | 1.8.22         |\n| 1.3.0             | 1.8.10         |\n| 1.2.1             | 1.7.21         |\n| 1.2.0             | 1.6.10         |\n| 1.1.0             | 1.5.32         |\n| 1.0.0             | 1.4.30         |\n\n## Miscellaneous\n\n* When calling `KmLogging.setLoggers()` the existing loggers are removed and the supplied ones are\n  added in.\n* If the existing ones should remain then `KmLogging.addLoggers()` should be used.\n* `PlatformLogger` uses Log on Android, os_log on iOS, SLF4j on JVM and console on WasmJS and JS.\n* If a custom logger is created that changes the log level dynamically such as from a Remote Config\n  change then `KmLogging.setupLoggingFlags()` should be called when the logger's log levels were\n  changed to calculate which log levels are enabled. KmLogging maintains variables for each log\n  level corresponding to whether any logger is enabled at that level. This is done for performance\n  reason so only a single boolean check will be done at runtime to minimize the overhead when\n  running in production. The android sample app demonstrates this.\n\n## Use in unit testing\n\n* If you want log messages to show up while unit testing then in your test class you can set up a\n  logger that prints to the console using something like:\n\n```kotlin\n    @BeforeTest\n    fun setup() {\n        KmLogging.setLoggers(PrintLogger(FixedLogLevel(true)))\n    }\n```\n\n* On Android unit tests will complain about not supplying default values or not being mocked. You\n  will want to include the following:\n\n```kotlin\nandroid {\n    testOptions {\n        unitTests {\n            isReturnDefaultValues = true\n        }\n    }\n}\n```\n\n## Logging to another system such as Crashlytics\n\nIf logging is only desired at certain levels that can be setup. For example, if only the more\nimportant logs should be sent to Crashlytics to give some context to crashes then only log info\nlevel and above. That can be easily done by by defining and adding in a logger to do that. The\nsample android app implement this.\n\n```kotlin\nclass CrashlyticsLogger : Logger {\n    override fun verbose(tag: String?, msg: String) {}\n\n    override fun debug(tag: String?, msg: String) {}\n\n    override fun info(tag: String?, msg: String) {\n        FirebaseCrashlytics.getInstance().log(msg)\n    }\n\n    override fun warn(tag: String?, msg: String, t: Throwable?) {\n        FirebaseCrashlytics.getInstance().log(msg)\n    }\n\n    override fun error(tag: String?, msg: String, t: Throwable?) {\n        FirebaseCrashlytics.getInstance().log(msg)\n    }\n\n    override fun isLoggingVerbose(): Boolean = false\n\n    override fun isLoggingDebug(): Boolean = false\n\n    override fun isLoggingInfo(): Boolean = true\n\n    override fun isLoggingWarning(): Boolean = true\n\n    override fun isLoggingError(): Boolean = true\n}\n\n// at App creation time configure logging\n// use addLogger to keep the existing loggers\n\nKmLogging.addLogger(CrashlyticsLogger())\n``` \n\n## Usage in iOS and Swift\n\nBy default the kotlin multiplatform toolchain will not export all KmLogging classes and those that\nare will be prefaced with the stringLogging.\nIf you want to use classes from Swift code you will need to direct the plugin to export the logging\nlibrary in your `build.gradle.kts`:\n\n```kotlin\n    ios {\n    binaries {\n        framework {\n            baseName = \"my-shared-module-name\"\n            export(\"com.diamondedge:logging:$logging_version\")\n        }\n    }\n}\n```\n\nNote: logging must also be included as an api dependency.\nSee https://kotlinlang.org/docs/reference/mpp-build-native-binaries.html\n\nThe code to figure out what class KmLog was instantiated from does not work from within Swift, so\nyou will always want to pass in the class name:\n\n```swift\nclass MyClass {\n    let log = KmLog(tag: \"MyClass\")\n}\n```\n\n## Usage on JVM\n\nYou will need to include a dependency on the logging library of your choice that is compatible with\nSLF4J. See the sample app which uses `logback`. Since SLF4J controls the log level using its own\nconfigurations it is advisable to retain the use of FixedLogLevel in the default configuration as\nthe log level controller. The log level controller in KmLogging controls the possibility of logging\noccurring with SLF4J controlling whether a particular log usage is output or not.\n\n## Usage in Libraries\n\nA best practice for libraries is to not have its logging turned on be default. If both a library and\nan application both use KmLogging then the library will have its logging turned on automatically. To\nenable or disable a library's logging independently of the application, the library needs to use a\nwrapper so logging can be turned on/off using a variable.\n\nExample usage with code implemented\nin [ChartsLogging.kt](https://github.com/ellsworthrw/DiamondCharts/blob/main/charts/src/main/java/com/diamondedge/charts/ChartsLogging.kt):\n\n```kotlin\n object ChartsLogging {\n    var enabled = true\n}\n\nfun moduleLogging(tag: String? = null): KmModuleLog {\n    // string passed into createTag should be the name of the class that this function is implemented in\n    // if it is a top level function then the class name is the file name with Kt appended\n    val t = tag ?: KmLogging.createTag(\"ChartsLoggingKt\").first\n    return KmModuleLog(logging(t), ChartsLogging::enabled)\n}\n```\n\nThe library code would then use this new function to do its logging:\n\n```kotlin\n    val log = moduleLogging()\n```\n\n## Quick migration of Android Log calls\n\nOnce you have adopted KmLogging, what do you do with all your existing Android code that is using\nthe Log class? The first quick and easy step is to switch all your code to using\ncom.diamondedge.logging.Log class which mimics the Android Log class but sends all output\nthrough KmLogging so you can turn it on and off at the same time as with all other KmLog usages and\nhave all its benefits. To do this simply replace all occurrences of `import android.util.Log` in\nyour code base with `import com.diamondedge.logging.Log`\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdiamondedge1%2Fkmlogging","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdiamondedge1%2Fkmlogging","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdiamondedge1%2Fkmlogging/lists"}