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

Allow logging to be disabled for individual classes #3

Open
wants to merge 6 commits into
base: main
Choose a base branch
from

Conversation

howyp
Copy link

@howyp howyp commented Feb 1, 2023

This adds a new OFF configuration which can be specified for a particular enclosure (ie. such as a class)in the RuntimeConfig.

This allows the logging to be completely disabled for that enclosure; previously it was only possible to raise the level up to ERROR.

@@ -71,12 +71,27 @@ object DynamicOdinConsoleLogger {

case class RuntimeConfig(
minLevel: Level,
levelMapping: Map[String, Level] = Map.empty
levelMapping: Map[String, LevelConfig] = Map.empty
Copy link
Contributor

Choose a reason for hiding this comment

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

Technically this should have failed the bincompat checks 🤔 as the type has changed, I'll try and work out why that isn't working.

In the meantime, I'm trying to think of the best way to make a bincompat change here and I think you might need to create a new case class that uses the new level config. Then have a smart constructor that takes this old style config and translates it to the new.

Copy link
Author

Choose a reason for hiding this comment

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

Ah, yes that's a good point. I'll see what I can do, but the bincompat doesn't fail locally for me either, which doesn't make me too confident that changes I make are actually ok.

Could it be that, because it's a type parameter it is technically bincompat because of erasure? That wouldn't seem right to be but....

Choose a reason for hiding this comment

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

Could it be that, because it's a type parameter it is technically bincompat because of erasure?

💯 that's how the JVM works. It won't save your from runtime errors, but it won't be a linking error.

Copy link

@jbwheatley jbwheatley Mar 16, 2023

Choose a reason for hiding this comment

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

Just looking at the bin compat guide. Would this maintain bin compat?

case class RuntimeConfig private (
      minLevel: Level,
      levelMapping: Map[String, Level] = Map.empty,
      disabledClasses: List[String] = Nil
) {
  def withDisabledClasses(disabled: List[String]) = ???
}
object RuntimeConfig {
    def apply(minLevel: Level, levelMapping: Map[String, Level] = Map.empty) = RuntimeConfig(minLevel, levelMapping)
}

Maybe the copy method needs fixing too, and not sure how if default args play a role or not

Comment on lines 80 to 93
sealed trait LevelConfig {
def toLevel: Option[Level]
}

object LevelConfig {
case object Trace extends LevelConfig { val toLevel = Some(Level.Trace) }
case object Debug extends LevelConfig { val toLevel = Some(Level.Debug) }
case object Info extends LevelConfig { val toLevel = Some(Level.Info) }
case object Warn extends LevelConfig { val toLevel = Some(Level.Warn) }
case object Error extends LevelConfig { val toLevel = Some(Level.Error) }
case object Off extends LevelConfig { val toLevel = None }

implicit val eq: Eq[LevelConfig] = cats.derived.semiauto.eq
}
Copy link
Contributor

Choose a reason for hiding this comment

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

Having an ADT here is nice, but it makes it hard to evolve the config model in a bincompat fashion, I think it might be better to use a value class here with a smart constructor that checks the string value.

)(make: RuntimeConfig => Logger[F])(implicit eq: Eq[RuntimeConfig])
extends DefaultLogger[F](level)
extends DefaultLogger[F](Level.Trace)
Copy link
Contributor

@janstenpickle janstenpickle Mar 16, 2023

Choose a reason for hiding this comment

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

This feels a bit dangerous. With this being set, we will inspect the ref on every log message, but it does at least mean that the level mapping can override the default level setting.

I.e. every trace/debug message will hit the ref via the submit implementation below, rather than being filtered beforehand by this level here.

I'm wondering whether we should re-introduce minLevel which is the "absolute" minimum and cannot be lowered at runtime to prevent trace messages from hitting the ref.

Comment on lines +100 to 111
test("lowers default-level config") {
PropF.forAllF { (messageBeforeChange: String, messageAfterChange: String) =>
val messages = runTest() { logger =>
logger.info(messageBeforeChange) >>
IO.sleep(10.millis) >>
logger.update(RuntimeConfig(defaultLevel = Level.Debug)) >>
logger.debug(messageAfterChange)
}
messages.map(_.map(_.message.value).toList).assertEquals(List(message1))
messages
.map(_.map(_.message.value).toList)
.assertEquals(List(messageBeforeChange, messageAfterChange))
}
Copy link
Contributor

Choose a reason for hiding this comment

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

This would have failed in the old implementation as the logging level of DynamicOdinConsoleLoggerImpl would have been set to what ever the original value in RuntimeConfig was. This meant that you could raise the logging level, but never lower it!

The knock on effect of this change is covered in this comment

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants