Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adds log4s logging to free and tagless #512

Merged
merged 9 commits into from
Jan 17, 2018
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,10 @@ lazy val config = jvmModule("config")
lazy val logging = module("logging")
.dependsOn(core)
.jvmSettings(
libraryDependencies += %%("journal-core")
libraryDependencies ++= Seq(
%%("journal-core"),
%%("log4s")
)
)
.jsSettings(
libraryDependencies += %%%("slogging")
Expand Down
35 changes: 34 additions & 1 deletion docs/src/main/tut/docs/patterns/logging/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,40 @@ The set of abstract operations of the `Logging` algebra are specified as follows
Each one of the operations corresponds to variations of `debug`, `error`, `info`, and `warn` which cover most use cases when performing logging in an application.

The _frees-logging_ module contains built-in interpreters for both Scala.jvm and Scala.js which you may use out of the box.
The JVM handler interpreter is based on the [Verizon's Journal Library](https://github.com/Verizon/journal) and the JS handler in [slogging](https://github.com/jokade/slogging).
The JVM handler interpreter is based on the [Verizon's Journal Library](https://github.com/Verizon/journal) and [Log4s wrapper](https://github.com/Log4s/log4s).
In addition, the JS handler interpreter is based on [slogging](https://github.com/jokade/slogging).

### Wrappers available

Freestyle logging supports two wrappers for logging messages, `journal` and `log4s`. These wrappers are only available for `free` and `tagless` in JVM.

You could use either both, depending on your requirements, and the usage would be quite similar.

To use `log4s`:

```tut:book
import freestyle.free._
import freestyle.free.implicits._
import freestyle.free.logging._
import freestyle.free.loggingJVM.log4s.implicits._

@module trait App {
val log: LoggingM
}
```

To use `journal`:

```tut:book
import freestyle.free._
import freestyle.free.implicits._
import freestyle.free.logging._
import freestyle.free.loggingJVM.journal.implicits._

@module trait App {
val log: LoggingM
}
```

### Example

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,6 @@
*/

package freestyle.free
package loggingJVM

object loggingJVM {

object implicits extends freestyle.tagless.loggingJVM.Implicits

}
object implicits extends freestyle.tagless.loggingJVM.journal.Implicits
21 changes: 21 additions & 0 deletions modules/logging/jvm/src/main/scala/free/journal.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
/*
* Copyright 2017-2018 47 Degrees, LLC. <http://www.47deg.com>
*
* 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.
*/

package freestyle.free
package loggingJVM
package journal

object implicits extends freestyle.tagless.loggingJVM.journal.Implicits
21 changes: 21 additions & 0 deletions modules/logging/jvm/src/main/scala/free/log4s.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
/*
* Copyright 2017-2018 47 Degrees, LLC. <http://www.47deg.com>
*
* 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.
*/

package freestyle.free
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am not much in favor of having multiple package declarations. IMHO, an import should be as explicit and restricted as reasonably possible. In this case, it is not needed.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Makes sense. Changed.

package loggingJVM
package log4s

object implicits extends freestyle.tagless.loggingJVM.log4s.Implicits
20 changes: 20 additions & 0 deletions modules/logging/jvm/src/main/scala/tagless/implicits.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
/*
* Copyright 2017-2018 47 Degrees, LLC. <http://www.47deg.com>
*
* 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.
*/

package freestyle.tagless
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as before.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Makes sense. Changed.

package loggingJVM

object implicits extends freestyle.tagless.loggingJVM.journal.Implicits
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,14 @@
*/

package freestyle.tagless
package loggingJVM

import cats.Applicative
import freestyle.logging._
import freestyle.tagless.logging._
import journal._
import _root_.journal._

object loggingJVM {
object journal {

sealed abstract class TaglessLoggingMHandler[M[_]] extends LoggingM.Handler[M] {

Expand Down
81 changes: 81 additions & 0 deletions modules/logging/jvm/src/main/scala/tagless/log4s.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
/*
* Copyright 2017-2018 47 Degrees, LLC. <http://www.47deg.com>
*
* 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.
*/

package freestyle.tagless
package loggingJVM

import cats.Applicative
import freestyle.logging._
import freestyle.tagless.logging._
import org.log4s._

object log4s {

sealed abstract class TaglessLoggingMHandler[M[_]] extends LoggingM.Handler[M] {

import sourcecode.{File, Line}

protected def withLogger[A](f: Logger => A): M[A]

def debug(msg: String, srcInfo: Boolean)(implicit line: Line, file: File): M[Unit] =
withLogger(_.debug(formatMessage(msg, srcInfo, line, file)))

def debugWithCause(msg: String, cause: Throwable, srcInfo: Boolean)(
implicit
line: Line,
file: File): M[Unit] =
withLogger(_.debug(cause)(formatMessage(msg, srcInfo, line, file)))

def error(msg: String, srcInfo: Boolean)(implicit line: Line, file: File): M[Unit] =
withLogger(_.error(formatMessage(msg, srcInfo, line, file)))

def errorWithCause(msg: String, cause: Throwable, srcInfo: Boolean)(
implicit
line: Line,
file: File): M[Unit] =
withLogger(_.error(cause)(formatMessage(msg, srcInfo, line, file)))

def info(msg: String, srcInfo: Boolean)(implicit line: Line, file: File): M[Unit] =
withLogger(_.info(formatMessage(msg, srcInfo, line, file)))

def infoWithCause(msg: String, cause: Throwable, srcInfo: Boolean)(
implicit
line: Line,
file: File): M[Unit] =
withLogger(_.info(cause)(formatMessage(msg, srcInfo, line, file)))

def warn(msg: String, srcInfo: Boolean)(implicit line: Line, file: File): M[Unit] =
withLogger(_.warn(formatMessage(msg, srcInfo, line, file)))

def warnWithCause(msg: String, cause: Throwable, srcInfo: Boolean)(
implicit
line: Line,
file: File): M[Unit] =
withLogger(_.warn(cause)(formatMessage(msg, srcInfo, line, file)))

}

trait Implicits {
implicit def taglessLoggingApplicative[M[_]: Applicative](
implicit log: Logger = getLogger("")): LoggingM.Handler[M] = new TaglessLoggingMHandler[M] {

protected def withLogger[A](f: Logger => A): M[A] = Applicative[M].pure(f(log))

}
}

object implicits extends Implicits
}
79 changes: 79 additions & 0 deletions modules/logging/jvm/src/test/scala/free/LoggingTestsJournal.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
/*
* Copyright 2017-2018 47 Degrees, LLC. <http://www.47deg.com>
*
* 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.
*/

package freestyle.free

import cats.instances.future._
import cats.{Id, Monad}
import freestyle.free.implicits._
import freestyle.free.loggingJVM.implicits._
import org.scalatest.{AsyncWordSpec, Matchers}

import scala.concurrent.{ExecutionContext, Future}
import scala.util.control.NoStackTrace

class LoggingTestsJournal extends AsyncWordSpec with Matchers {

implicit override def executionContext = ExecutionContext.Implicits.global

import algebras._

"Logging Freestyle free integration journal" should {

case object Cause extends Exception("kaboom") with NoStackTrace

"allow a log message to be interleaved inside a program monadic flow" in {
val program = for {
a <- app.nonLogging.x
_ <- app.loggingM.debug("Debug Message", sourceAndLineInfo = true)
_ <- app.loggingM.debugWithCause("Debug Message", Cause)
_ <- app.loggingM.error("Error Message")
_ <- app.loggingM.errorWithCause("Error Message", Cause)
_ <- app.loggingM.info("Info Message")
_ <- app.loggingM.infoWithCause("Info Message", Cause)
_ <- app.loggingM.warn("Warning Message")
_ <- app.loggingM.warnWithCause("Warning Message", Cause)
b <- FreeS.pure(1)
} yield a + b
program.interpret[Future] map { _ shouldBe 2 }
}

"not depend on MonadError, thus allowing use of Monads without MonadError, like Id, for test algebras" in {
val program = for {
a <- app.nonLogging.x
_ <- app.loggingM.info("Info Message")
_ <- app.loggingM.infoWithCause("Info Message", Cause)
b <- FreeS.pure(1)
} yield a + b
program.interpret[TestAlgebra].run("configHere") shouldBe 2
}

"allow injecting a Logger instance" in {
val program = for {
a <- FreeS.pure(1)
_ <- app.loggingM.info("Info Message")
_ <- app.loggingM.error("Error Message")
b <- FreeS.pure(1)
} yield a + b

implicit val logger = journal.Logger("Potatoes")

program
.interpret[TestAlgebra]
.run("configHere") shouldEqual 2
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,13 +25,13 @@ import org.scalatest.{AsyncWordSpec, Matchers}
import scala.concurrent.{ExecutionContext, Future}
import scala.util.control.NoStackTrace

class LoggingTests extends AsyncWordSpec with Matchers {
class LoggingTestsLog4s extends AsyncWordSpec with Matchers {

implicit override def executionContext = ExecutionContext.Implicits.global

import algebras._

"Logging Freestyle free integration" should {
"Logging Freestyle free integration log4s" should {

case object Cause extends Exception("kaboom") with NoStackTrace

Expand Down
Loading