{"id":13566561,"url":"https://github.com/typelevel/log4cats","last_synced_at":"2025-07-31T08:46:00.052Z","repository":{"id":37105782,"uuid":"130877526","full_name":"typelevel/log4cats","owner":"typelevel","description":"Logging Tools For Interaction with cats-effect","archived":false,"fork":false,"pushed_at":"2024-10-28T17:11:25.000Z","size":2492,"stargazers_count":401,"open_issues_count":22,"forks_count":74,"subscribers_count":15,"default_branch":"main","last_synced_at":"2024-10-29T21:05:57.473Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"https://typelevel.org/log4cats/","language":"Scala","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/typelevel.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","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":"2018-04-24T15:41:21.000Z","updated_at":"2024-10-28T17:11:29.000Z","dependencies_parsed_at":"2023-02-13T15:30:45.788Z","dependency_job_id":"c5de1822-181a-419b-ba1e-0641b474ba80","html_url":"https://github.com/typelevel/log4cats","commit_stats":{"total_commits":1003,"total_committers":47,"mean_commits":"21.340425531914892","dds":0.6979062811565304,"last_synced_commit":"a4191f963812ed71158d3c84ca9863998e8dc9ea"},"previous_names":["christopherdavenport/log4cats"],"tags_count":53,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/typelevel%2Flog4cats","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/typelevel%2Flog4cats/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/typelevel%2Flog4cats/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/typelevel%2Flog4cats/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/typelevel","download_url":"https://codeload.github.com/typelevel/log4cats/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":246777791,"owners_count":20832033,"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":[],"created_at":"2024-08-01T13:02:12.085Z","updated_at":"2025-04-04T00:31:00.230Z","avatar_url":"https://github.com/typelevel.png","language":"Scala","funding_links":[],"categories":["Scala"],"sub_categories":[],"readme":"# log4cats [![Build Status](https://github.com/typelevel/log4cats/workflows/Continuous%20Integration/badge.svg?branch=main)](https://github.com/typelevel/log4cats/actions?query=branch%3Amain+workflow%3A%22Continuous+Integration%22) [![Maven Central](https://maven-badges.herokuapp.com/maven-central/org.typelevel/log4cats-core_2.12/badge.svg)](https://maven-badges.herokuapp.com/maven-central/org.typelevel/log4cats-core_2.12)\n\n## Project Goals\n\nlog4cats attempts to make referentially transparent logging a reality. These F algebras allow you to write\ncode for logging knowing you won't be doing side-effects as it offers no way to do so. We provide our own slf4j layer,\nor you can use any of the supported backends, or create your own.\n\n## Quick Start\n\nTo use log4cats in an existing SBT project with Scala 2.12 or a later version, add the following dependency to your\n`build.sbt`:\n\n```scala\nlibraryDependencies ++= Seq(\n  \"org.typelevel\" %% \"log4cats-core\"    % \"\u003cversion\u003e\",  // Only if you want to Support Any Backend\n  \"org.typelevel\" %% \"log4cats-slf4j\"   % \"\u003cversion\u003e\",  // Direct Slf4j Support - Recommended\n)\n```\n\n## Why log4cats?\n\nWell, to answer that, let's take a look at how you might combine cats-effect with vanilla logging...\n\n```scala\nobject MyVanillaLoggingThing {\n  val logger: Logger = Logger(LoggerFactory.getLogger(getClass.getName))\n  \n  def doSomething(): IO[Unit] =\n    IO(logger.info(\"Doing something!\")) *\u003e IO.println(\"Hello, World!\")\n\n}\n```\n\nBut what if you don't want to wrap your logger in an `IO` like this?  \nGood news, you don't have to!  Enter log4cats!  Read on!\n\n## Examples\n\n```scala\nimport org.typelevel.log4cats.Logger\nimport org.typelevel.log4cats.slf4j.Slf4jLogger\nimport cats.effect.Sync\nimport cats.syntax.all.*\n\nobject MyThing {\n  // Impure But What 90% of Folks I know do with log4s\n  implicit def unsafeLogger[F[_]: Sync] = Slf4jLogger.getLogger[F]\n\n  // Arbitrary Local Function Declaration\n  def doSomething[F[_]: Sync]: F[Unit] =\n    Logger[F].info(\"Logging Start Something\") *\u003e\n            Sync[F].delay(println(\"I could be doing anything\"))\n                    .attempt.flatMap {\n                      case Left(e) =\u003e Logger[F].error(e)(\"Something Went Wrong\")\n                      case Right(_) =\u003e Sync[F].pure(())\n                    }\n\n  def safelyDoThings[F[_]: Sync]: F[Unit] = for {\n    logger \u003c- Slf4jLogger.create[F]\n    _ \u003c- logger.info(\"Logging at start of safelyDoThings\")\n    something \u003c- Sync[F].delay(println(\"I could do anything\"))\n            .onError { case e =\u003e logger.error(e)(\"Something Went Wrong in safelyDoThings\") }\n    _ \u003c- logger.info(\"Logging at end of safelyDoThings\")\n  } yield something\n\n  def passForEasierUse[F[_]: Sync : Logger] = for {\n    _ \u003c- Logger[F].info(\"Logging at start of passForEasierUse\")\n    something \u003c- Sync[F].delay(println(\"I could do anything\"))\n            .onError { case e =\u003e Logger[F].error(e)(\"Something Went Wrong in passForEasierUse\") }\n    _ \u003c- Logger[F].info(\"Logging at end of passForEasierUse\")\n  } yield something\n}\n```\n\n## Wait...why log4cats again?\nIf you compare the vanilla logger + cats-effect example with the log4cats examples above,\nyou might be asking yourself \"why do I have to do any of this?\" \nor \"why can't I just add a log statement like normal?\"  \n\nWell there are several reasons.  Logging is often times an overlooked side-effect, \nwhich under the hood can range from writing to a mutable queue, writing to disk, \noutputting to the console, or sometimes even doing network I/O! \nTo correctly deal with these kinds of side-effects we have to ensure they are properly wrapped in `IO`,\nsee the [cats-effect docs](https://typelevel.org/cats-effect/docs/concepts#side-effects) for more details.\n\nBasically, we are using cats-effect.  We like things like \"referential transparency\" \nand \"programs-as-values\".  Wrapping our log statement in an `IO` helps with that.\n\n### Laconic syntax\n\nIt's possible to use interpolated syntax for logging.\nCurrently, supported ops are: `trace`, `debug`, `info`, `warn`, `error`.\nYou can use it for your custom `Logger` as well as for Slf4j `Logger`.\n\n```scala\nimport cats.Applicative\nimport cats.effect.Sync\nimport org.typelevel.log4cats.Logger\nimport org.typelevel.log4cats.syntax.*\n\ndef successComputation[F[_]: Applicative]: F[Int] = Applicative[F].pure(1)\ndef errorComputation[F[_]: Sync]: F[Unit] = Sync[F].raiseError[Unit](new Throwable(\"Sorry!\"))\n\ndef log[F[_]: Sync : Logger] =\n  for {\n    result1 \u003c- successComputation[F]\n    _ \u003c- info\"First result is $result1\"\n    _ \u003c- errorComputation[F].onError(_ =\u003e error\"We got an error!\")\n  } yield ()\n```\n\n## Logging using capabilities\n\nYou can work with logging using capabilities. It's implemented via the `LoggerFactory` trait.\nYou instantiate it once (dependent on the specific logging backend you use)\nand pass this around in your application.\n\nThis brings several advantages:\n\n* it's no more needed to pass the very powerful `F[_]: Sync` constraint everywhere \n  that can do almost anything when you only need logging.\n* you have control of loggers creation, and you can even add in whatever custom\n  functionality you need for your applications here. E.g. create loggers that also push logs\n  to some external providers by giving a custom implementation of this trait.\n\nIf you are unsure how to create a new `LoggerFactory[F]` instance, then you can look at the `log4cats-slf4j`,\nor `log4cats-noop` modules for concrete implementations.\n\nThe quickest fix might be to import needed implicits:\n\n```scala\n// assumes dependency on log4cats-slf4j module\n\nimport org.typelevel.log4cats.*\nimport org.typelevel.log4cats.slf4j.*\n\nval logger: SelfAwareStructuredLogger[IO] = LoggerFactory[IO].getLogger\n\n// or\ndef anyFSyncLogger[F[_]: Sync]: SelfAwareStructuredLogger[F] = Slf4jFactory[F].getLogger\n```\n\nAlternatively, a mutually exclusive solution is to explicitly create your\n`LoggerFactory[F]` instance and pass them around implicitly:\n\n```scala\nimport cats.effect.IO\nimport cats.Monad\nimport cats.syntax.all.*\nimport org.typelevel.log4cats.*\nimport org.typelevel.log4cats.slf4j.Slf4jFactory\n\n// create our LoggerFactory\nimplicit val logging: LoggerFactory[IO] = Slf4jFactory[IO]\n\n// we summon LoggerFactory instance, and create logger\nval logger: SelfAwareStructuredLogger[IO] = LoggerFactory[IO].getLogger\nlogger.info(\"logging in IO!\"): IO[Unit]\n\n// basic example of a service using LoggerFactory\nclass LoggerUsingService[F[_]: LoggerFactory : Monad] {\n  val logger = LoggerFactory[F].getLogger\n\n  def use(args: String): F[Unit] =\n    for {\n      _ \u003c- logger.info(\"yay! effect polymorphic code\")\n      _ \u003c- logger.debug(s\"and $args\")\n    } yield ()\n}\n\nnew LoggerUsingService[IO].use(\"foo\")\n```\n\n## Using log4cats in tests\n\nSee [here](testing/README.md) for details\n\n## CVE-2021-44228 (\"log4shell\")\n\nlog4cats is not directly susceptible to CVS-2021-44228.  The\nlog4cats-slf4j implementation delegates all logging operations to\n[slf4j][slf4j].  if you use log4cats-slf4j, your configured slf4j\nprovider may put you at risk.  See [slf4j's comments on\nCVE-2021-44228][slf4j-log4shell] for more.\n\n[slf4j]: https://www.slf4j.org/\n[slf4j-log4shell]: https://www.slf4j.org/log4shell.html\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftypelevel%2Flog4cats","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftypelevel%2Flog4cats","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftypelevel%2Flog4cats/lists"}