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

Replace Log with stdlib logger #133

Closed
wants to merge 0 commits into from

Conversation

rkallos
Copy link
Contributor

@rkallos rkallos commented Jun 7, 2020

Closes #127

@rkallos
Copy link
Contributor Author

rkallos commented Jun 7, 2020

Upon further reading, should I change the loggers to all print to a single fd to also fix #121?

.> append(level.string())
.> append(": ")
.> append(msg)
primitive LevelLogFormatter
Copy link
Member

Choose a reason for hiding this comment

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

Where is this used? I'm wondering how valuable it is at the point.


interface val LogFormatter
fun apply(level: LogLevel, msg: String, loc: SourceLoc): String
use "logger"

primitive CodeLogFormatter is LogFormatter
Copy link
Member

Choose a reason for hiding this comment

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

Where is this used? I'm wondering how valuable it is at the point.


primitive CodeLogFormatter is LogFormatter
fun apply(level: LogLevel, msg: String, loc: SourceLoc): String =>
Copy link
Member

Choose a reason for hiding this comment

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

I assume the log level where was so it would be polymorphic. Did you see that there's no need for being able to switch between these formatters?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Log level was there because log.pony had its own implementation of LogFormatter which accepted a log level argument. The log level argument was used in LevelLogFormatter to prepend the log message type to the message being logged.

Copy link
Member

Choose a reason for hiding this comment

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

Yup that makes sense now. I like how you moved the log level to being purely at the top level.

Some package level comments for the logging subsystem for corral that details how the different parts work together should be added the PR so that folks in the future won't be asking the same questions.


primitive SimpleLogFormatter is LogFormatter
fun apply(level: LogLevel, msg: String, loc: SourceLoc): String =>
Copy link
Member

Choose a reason for hiding this comment

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

I assume the log level where was so it would be polymorphic. Did you see that there's no need for being able to switch between these formatters?

.> append(": ")
.> append(msg)
primitive LevelLogFormatter
fun apply(level: LogLevel): LogFormatter =>
Copy link
Member

Choose a reason for hiding this comment

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

this seems odd. it only takes a log level?

How is this being used? The lambda concerns me. I'm not sure why that is 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.

If I understand the original code properly, the previous LevelLogFormatter prepended the log type (fine, info, warn, error) to the message being logged. It is only used in main.pony, either as a one-off before exiting or after parsing the command line arguments.

If you like, I could get rid of it by changing the call sites to add the log message type.

Copy link
Member

Choose a reason for hiding this comment

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

Ah so the existing pony standard library logger doesn't have the log level. That makes sense. So, this wraps every log call later and appends the level. That makes sense.

Can you add some doc comments to both the apply method and the primitive to make clear what it is doing?

@@ -1,4 +0,0 @@
class val Error
Copy link
Member

Choose a reason for hiding this comment

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

was this not used?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I removed it because it clashed with logger.Error, and it only ever held strings to be passed to a logger.

Copy link
Member

Choose a reason for hiding this comment

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

Makes sense.

@SeanTAllen
Copy link
Member

Upon further reading, should I change the loggers to all print to a single fd to also fix #121?

No. That's more of a "let's look into the interleaving and make sure its not a bug".

dir = dir'
log = log'
info = InfoData(JsonObject)
log.info("Created bundle in " + dir.path)
log(Info) and log.log("Created bundle in " + dir.path)
Copy link
Member

Choose a reason for hiding this comment

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

here's a question, should there be a "Log" class for corral that keeps the previous form of different methods and it contains the Logger actor and the check to see whether to send a message? It's certainly cleaner and hides to log(Info).

By hiding that, we could have single comments per method on the Logger class that explains why that is done to short circuit sending a message to the actor.

It might make the code base more approachable for folks who don't really know Pony.

Thoughts?

I'm not sure how that would come together with the other changes. Perhaps it might be problematic. I'm not sure.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I looked into that approach, but when I read the docs for the logger package and noticed the use of boolean short-circuiting to avoid the work of building strings, I didn't see a clear way to preserve the encapsulation provided by Log and to get the near zero-cost logging offered by the logger API. That's why I chose to replace all the call sites with the idiomatic use of logger.

Copy link
Member

Choose a reason for hiding this comment

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

Makes sense.

Copy link
Member

Choose a reason for hiding this comment

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

It's amusing that you are reminding me of this given that I wrote those docs for the logger package after writing the logger package.

😆

@SeanTAllen
Copy link
Member

This looks good aside from needing some documentation for the corral logging package and a couple of the "trickier" formatter usages.

@SeanTAllen
Copy link
Member

@rkallos this will need to be rebased as it now has conflicts with changes in cmd_update.pony

@rkallos rkallos force-pushed the use-stdlib-logger branch from 8393e2a to 23800fd Compare June 7, 2020 12:44
@rkallos
Copy link
Contributor Author

rkallos commented Jun 7, 2020

Rebased 😃

@SeanTAllen
Copy link
Member

Looks like you have compilation errors after the rebase.

@rkallos
Copy link
Contributor Author

rkallos commented Jun 7, 2020

Note to self: Run tests locally after rebasing.

@rkallos rkallos force-pushed the use-stdlib-logger branch from 23800fd to c99ef75 Compare June 7, 2020 12:48
@SeanTAllen
Copy link
Member

SeanTAllen commented Jun 7, 2020

@rkallos ping me after you've had time to add the documentation/comments and I'll have another look. I might be delayed as I'm moving next weekend and most of my time is going towards work and the move at the moment.

.> append(msg)
primitive LevelLogFormatter
"""
LevelLogFormatter produces LogFormatters that prepend a log level to entries.
Copy link
Member

Choose a reason for hiding this comment

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

This doesn't really feel like explains the purpose.

We want to have the log level in all the output for filtering, searching etc that folks might want to do with an unstructured log.

Rather than adding the format to each string at all call locations, we create one of these in main that in turn wraps the other formatters appending the log-level"

That's more than the comment for this primitive, but part of that should be included in this primitive.

I'd like to see log.pony moved from corral/util to corral/log or corral/logging and have a package level doc as well that explains the relationship between this logger and the others and how logging is in general used in corral (as detailed above).

Including the discussion about the short circuit that your commit switched to.

Basically cover everything that I felt the need to ask you about as part oft this PR.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Thank you for the clarification. I've added some more clarification. Let me know what you think.

work of building strings that won't get logged. This can make log statements
somewhat verbose:

```
Copy link
Member

Choose a reason for hiding this comment

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

can you pony codefence type?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done. It's pony, not ponylang, right?

Copy link
Member

Choose a reason for hiding this comment

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

correct

@rkallos rkallos force-pushed the use-stdlib-logger branch from 627590c to c5545fd Compare June 7, 2020 14:10
LevelLogFormatter is used by the logger(s) created in Main.
"""
fun apply(level: LogLevel): LogFormatter =>
"""
Copy link
Member

Choose a reason for hiding this comment

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

Lines 33 to 35 should be most of the apply method comment.

Creates lambda to... blah blah blah.

sites by creating a special-purpose LogFormatter whose sole purpose is to
prepend the log level.

LevelLogFormatter is used by the logger(s) created in Main.
Copy link
Member

Choose a reason for hiding this comment

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

information from 33 to 37 should be in the package level comments.

@@ -0,0 +1,64 @@
"""
# Logging in corral

Copy link
Member

Choose a reason for hiding this comment

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

I think the most important thing for the package docs is to detail the various components and how they interact so...

uses Pony standard logging.

There's a log level formatter that acts as a wrapper around others so that we get INFO etc output without having to spread throughout the codebase.

And here is how it is used with other formatters.

@SeanTAllen
Copy link
Member

I left some more docs comments. I think what is really missing is, particularly at the package level is...

Written for someone who is coming in to modify logging, add new functionality.

Description of how logging is done and works.

How formatters interact with one another.

What each formatter does.

Basically what you need to be aware of to make changes.

I hope that makes sense. Not sure if it does.

@SeanTAllen
Copy link
Member

I had to run an errand... that lead to a thought.

For the documentation, there are two audiences.

People who want to enhance/change the logging that exists.
People who are going to add logging to new parts of corral.

The basic informational needs of both groups should be met.

@rkallos
Copy link
Contributor Author

rkallos commented Jun 7, 2020

Upon further reflection, I think my approach with LevelLogFormatter is incorrect. It prepends the same log level to all log messages, regardless of user intent:

let logger = StringLogger(Info, env.err, LevelLogFormatter(Info))
logger(Error) and logger.log("some error message")
// logs "INFO: some error message"

To fix this, I think I will introduce a new primitive that accepts a log level and a string and does the prepending there. The resulting code should look like this:

let logger = StringLogger(Info, env.err)
logger(Error) and logger.log(LogMsg(Error, "some error message"))
// logs "ERRR: some error message"

This avoids the downside of having Log be a sort of wrapper class around Logger (not being able to save on work via short-circuiting) while also removing the need for LevelLogFormatter.

Alternately, this might make a compelling argument for adding a log_level argument to the LogFormatter interface in the standard library, though that would require a great deal of care; it seems like it would be a breaking change.

@SeanTAllen
Copy link
Member

@rkallos This is a good real world use case for the standard library logger. I think it might have highlighted a need for the inclusion of Log Level in the LogFormatter stdlib interface.

Would you be up to opening an RFC to make that change? It's small but we need to run it by people. I'm fully in support of it.

This PR could then be updated so that it would be a small change to finish off and merge once the standard library has been updated.

@rkallos
Copy link
Contributor Author

rkallos commented Jun 7, 2020

New RFC

@rkallos rkallos force-pushed the use-stdlib-logger branch from c5545fd to a77f4d9 Compare July 31, 2020 22:24
@rkallos rkallos closed this Jul 31, 2020
@rkallos rkallos force-pushed the use-stdlib-logger branch from a77f4d9 to fb97117 Compare July 31, 2020 22:28
@rkallos
Copy link
Contributor Author

rkallos commented Jul 31, 2020

Now that 0.36.0 is out, work on this can continue. It'd probably be best if I started over, as a lot of the details are now lost to me.

@rkallos rkallos deleted the use-stdlib-logger branch September 23, 2020 12:20
@ergl ergl mentioned this pull request Jun 30, 2021
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.

Corral should use the ponyc standard library logger
2 participants