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

implement ConsoleLogger for Scala.js #694

Merged
merged 10 commits into from
Dec 8, 2022
4 changes: 2 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -119,11 +119,11 @@ jobs:

- name: Make target directories
if: github.event_name != 'pull_request' && (startsWith(github.ref, 'refs/tags/v') || github.ref == 'refs/heads/main')
run: mkdir -p testing/jvm/target noop/jvm/target target .js/target core/native/target site/target testing/native/target noop/native/target core/js/target testing/js/target noop/js/target core/jvm/target .jvm/target .native/target slf4j/target project/target
run: mkdir -p testing/jvm/target noop/jvm/target target .js/target core/native/target site/target testing/native/target noop/native/target core/js/target js-console/target testing/js/target noop/js/target core/jvm/target .jvm/target .native/target slf4j/target project/target

- name: Compress target directories
if: github.event_name != 'pull_request' && (startsWith(github.ref, 'refs/tags/v') || github.ref == 'refs/heads/main')
run: tar cf targets.tar testing/jvm/target noop/jvm/target target .js/target core/native/target site/target testing/native/target noop/native/target core/js/target testing/js/target noop/js/target core/jvm/target .jvm/target .native/target slf4j/target project/target
run: tar cf targets.tar testing/jvm/target noop/jvm/target target .js/target core/native/target site/target testing/native/target noop/native/target core/js/target js-console/target testing/js/target noop/js/target core/jvm/target .jvm/target .native/target slf4j/target project/target

- name: Upload target directories
if: github.event_name != 'pull_request' && (startsWith(github.ref, 'refs/tags/v') || github.ref == 'refs/heads/main')
Expand Down
14 changes: 13 additions & 1 deletion build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ val logbackClassicV = "1.2.11"

Global / onChangedBuildSource := ReloadOnSourceChanges

lazy val root = tlCrossRootProject.aggregate(core, testing, noop, slf4j, docs)
lazy val root = tlCrossRootProject.aggregate(core, testing, noop, slf4j, docs, `js-console`)

lazy val docs = project
.in(file("site"))
Expand Down Expand Up @@ -92,6 +92,18 @@ lazy val slf4j = project
}
)

lazy val `js-console` = project
.settings(commonSettings)
.dependsOn(core.js)
.settings(
name := "log4cats-js-console",
tlVersionIntroduced := List("2.12", "2.13", "3").map(_ -> "2.6.0").toMap,
libraryDependencies ++= Seq(
"org.typelevel" %%% "cats-effect-kernel" % catsEffectV
)
)
.enablePlugins(ScalaJSPlugin)

lazy val commonSettings = Seq(
libraryDependencies ++= Seq(
"org.typelevel" %%% "munit-cats-effect" % munitCatsEffectV % Test
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
/*
* Copyright 2018 Typelevel
*
* 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.
*/

/* All documentation for facades is thanks to Mozilla Contributors at https://developer.mozilla.org/en-US/docs/Web/API
* and available under the Creative Commons Attribution-ShareAlike v2.5 or later.
* http://creativecommons.org/licenses/by-sa/2.5/
*
* Everything else is under the MIT License http://opensource.org/licenses/MIT
*/

package org.typelevel.log4cats.console

import scala.scalajs.js
import scala.scalajs.js.annotation.JSGlobal

/**
* The console object provides access to the browser's debugging console. The specifics of how it
* works vary from browser to browser, but there is a de facto set of features that are typically
* provided.
*
* There are more methods available; this is the minimal façade needed for console logging from
* log4cats.
*/
@js.native
@JSGlobal("console")
private[console] object Console extends js.Object {

/**
* Outputs an informational message to the Web Console. In Firefox, a small "i" icon is displayed
* next to these items in the Web Console's log.
*/
def info(message: Any, optionalParams: Any*): Unit = js.native

/**
* Outputs a warning message. You may use string substitution and additional arguments with this
* method. See Using string substitutions.
*/
def warn(message: Any, optionalParams: Any*): Unit = js.native

/**
* Outputs an error message. You may use string substitution and additional arguments with this
* method. See Using string substitutions.
*/
def error(message: Any, optionalParams: Any*): Unit = js.native

/**
* Outputs a debug message. You may use string substitution and additional arguments with this
* method. See Using string substitutions.
*/
def debug(message: Any, optionalParams: Any*): Unit = js.native
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
/*
* Copyright 2018 Typelevel
*
* 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 org.typelevel.log4cats
package console

import cats.effect.kernel.Sync

private[console] class ConsoleF[F[_]: Sync] {
def info(message: Any, optionalParams: Any*): F[Unit] =
Sync[F].delay(Console.info(message, optionalParams: _*))
def warn(message: Any, optionalParams: Any*): F[Unit] =
Sync[F].delay(Console.warn(message, optionalParams: _*))
def error(message: Any, optionalParams: Any*): F[Unit] =
Sync[F].delay(Console.error(message, optionalParams: _*))
def debug(message: Any, optionalParams: Any*): F[Unit] =
Sync[F].delay(Console.debug(message, optionalParams: _*))
}

private[console] object ConsoleF {
def apply[F[_]: ConsoleF]: ConsoleF[F] = implicitly

implicit def syncInstance[F[_]: Sync]: ConsoleF[F] = new ConsoleF[F]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
/*
* Copyright 2018 Typelevel
*
* 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 org.typelevel.log4cats
package console

import cats.effect.kernel.Sync
import cats.syntax.all._
import org.typelevel.log4cats.extras.LogLevel
import org.typelevel.log4cats.extras.LogLevel._

class ConsoleLogger[F[_]: Sync](logLevel: Option[LogLevel] = Option(Trace))
extends SelfAwareStructuredLogger[F] {
private val ConsoleF: ConsoleF[F] = implicitly
override def trace(t: Throwable)(message: => String): F[Unit] = ConsoleF.debug(message, t)
override def trace(message: => String): F[Unit] = ConsoleF.debug(message)
override def isTraceEnabled: F[Boolean] = logLevel.exists(_ <= Trace).pure[F]

override def debug(t: Throwable)(message: => String): F[Unit] = ConsoleF.debug(message, t)
override def debug(message: => String): F[Unit] = ConsoleF.debug(message)
override def isDebugEnabled: F[Boolean] = logLevel.exists(_ <= Debug).pure[F]

override def info(t: Throwable)(message: => String): F[Unit] = ConsoleF.info(message, t)
override def info(message: => String): F[Unit] = ConsoleF.info(message)
override def isInfoEnabled: F[Boolean] = logLevel.exists(_ <= Info).pure[F]

override def warn(t: Throwable)(message: => String): F[Unit] = ConsoleF.warn(message, t)
override def warn(message: => String): F[Unit] = ConsoleF.warn(message)
override def isWarnEnabled: F[Boolean] = logLevel.exists(_ <= Warn).pure[F]

override def error(t: Throwable)(message: => String): F[Unit] = ConsoleF.error(message, t)
override def error(message: => String): F[Unit] = ConsoleF.error(message)
override def isErrorEnabled: F[Boolean] = logLevel.exists(_ <= Error).pure[F]

/*
* ConsoleLogger should probably not extend from StructuredLogger, because there's not
* a good way to use the context map on this platform. However, LoggerFactory forces
* its LoggerType to extend SelfAwareStructuredLogger, and since that's the factory
* type that is well documented, that's what is demanded everywhere. Therefore, to be
* useful, we implement the context variants below, but completely ignore the context
* map parameters.
*/
override def trace(ctx: Map[String, String])(msg: => String): F[Unit] = trace(msg)
override def trace(ctx: Map[String, String], t: Throwable)(msg: => String): F[Unit] =
trace(t)(msg)
override def debug(ctx: Map[String, String])(msg: => String): F[Unit] = debug(msg)
override def debug(ctx: Map[String, String], t: Throwable)(msg: => String): F[Unit] =
debug(t)(msg)
override def info(ctx: Map[String, String])(msg: => String): F[Unit] = info(msg)
override def info(ctx: Map[String, String], t: Throwable)(msg: => String): F[Unit] = info(t)(msg)
override def warn(ctx: Map[String, String])(msg: => String): F[Unit] = warn(msg)
override def warn(ctx: Map[String, String], t: Throwable)(msg: => String): F[Unit] = warn(t)(msg)
override def error(ctx: Map[String, String])(msg: => String): F[Unit] = error(msg)
override def error(ctx: Map[String, String], t: Throwable)(msg: => String): F[Unit] =
error(t)(msg)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
/*
* Copyright 2018 Typelevel
*
* 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 org.typelevel.log4cats
package console

import cats.effect.kernel._
import cats.syntax.all._

trait ConsoleLoggerFactory[F[_]] extends LoggerFactory[F]

object ConsoleLoggerFactory {
def apply[F[_]: ConsoleLoggerFactory]: ConsoleLoggerFactory[F] = implicitly

def create[F[_]: Sync]: ConsoleLoggerFactory[F] = new ConsoleLoggerFactory[F] {
override def getLoggerFromName(name: String): SelfAwareStructuredLogger[F] =
new ConsoleLogger[F]()

override def fromName(name: String): F[SelfAwareStructuredLogger[F]] =
getLoggerFromName(name).pure[F].widen
}
}