Refactored to singleton logger#483
Conversation
leventeBajczi
left a comment
There was a problem hiding this comment.
Thanks for the changes, I think these really help clear up the logging infrastructure of Theta!
I've skimmed through the changes, and these were my initial impressions. Please take a look -- but overall, I'm really happy with this PR.
|
|
||
| @Parameter( | ||
| names = {"--grep", "-grep"}, | ||
| description = "Log type pattern for the new logger API") |
There was a problem hiding this comment.
Saying "new" won't age well, just say "Log type pattern" -- also, add a line of documentation on its use with an example (either here as a comment, or in one of the doc markdown files)
There was a problem hiding this comment.
Also, explicitly say that either this pattern, or -- if not given -- the loglevel takes effect, but never their conjunction.
There was a problem hiding this comment.
I will need to take a closer look at this file. However, what I can already say, is that I don't like to see "yices" here -- that is very specific to one half-supported SMT solver. Can you give a reason why that is here, but no other solver is?
There was a problem hiding this comment.
That is just me trying to use the logger and giving an example how I accept it to be used in the future. Yices is not special at all its just where I spend more time trying to find a workaround to the SSL expired certificate problem, and therefore I used the logger their more extensively so I can also use it as a concreate example. The main idea is that eventually every class will have a type. (and also subtypes with in the that class type, is a tree of types with "grep" used to query it).
Lets suppose that I want to get the logs inside the CegarChecker. I would put as type:
INFO_CEGARCHECKER-> create a func infoCegarCheckerMAINSTEP_CEGARCHECKER-> create a func mainstepCegarCheckerSUBSTEP_CEGARCHECKER-> create a func substepCegarChecker
when I initialize with Logger.init("MAINSTEP|SUBSTEP") I would have both theMAINSTEP_CEGARCHECKER,SUBSTEP_CEGARCHECKER(and all the other types that have a substring ofMAINSTEPandSUBSTEP). But if I want onlyCEGARCHECKERthen Logger.init("CEGARCHECKER") and it will showSUBSTEP_CEGARCHECKER,MAINSTEP_CEGARCHECKERandINFO_CEGARCHECKER.
Sorry I didn't do it justice explaining how it works. I will have to write better docs.
There was a problem hiding this comment.
So, familiarizing myself with the logger, the main idea is that you have a more complex filtering than just a few levels of increasing verbosity. I think the filtering side (how you use --grep) is mostly clear to me.
My question is rather about how and where the possible values that are filtered are defined.
Here is what I understand about that:
I see the logTypes in the logger. I see that level is passed as a string to the log method and I see the enabled set. I can see that enabled just contains all matches of logTypes to the regex from --grep.
I think what Levi did not like (or will not like? :D ) is that someone implementing something new - let's say a new checker - will have to think about adding stuff in the logger. So the logger becomes cluttered with information from literally everywhere in Theta, and logTypes becomes huge.
I did not fully think the solution through, but I think there are roughly two directions:
- the central
logTypescollection of all the log types is avoided and these values should be distributed, e.g., per class/per file. Something likeSTMT_LABELs and things like that - an extra "utility" constant. Pro: if I develop a new checker, I just add a constant or two and I instantly have a working, customized logger; (BIG) Con: extra constant value in practically every file - I think the other solution is to just keep
logTypes, expect it to be huge and try to make that usable and maintainable - put it in it's own file and somehow make it foolproof in a way so that I don't forget to add my new log values to the new log checker
Also, the question is: how much do we plan to fill up logTypes right now? Do we want to 1) go through a lot of places and add a lot of custom log types OR 2) do we do it gradually - e.g., you add what you needed (yices, cegar, whatever) and the next person who needs it elsewhere, say IC3, can add it there. I would prefer the latter - just with some really well shown / highlighted doc, so that people know that they can do this?
(I'm curious about everyone's and anyone's input on this.)
There was a problem hiding this comment.
I prefer having one file witch contains all the logTypes (option 2). I like it more for maintainability. Why?
- You can simply answer the question without searching the codebase: What logger types can I use?
- How can i use a logger type in many places in the codebase, in other words how do I pass the logger type around?
the central logTypes collection of all the log types is avoided and these values should be distributed, e.g., per class/per file. Something like STMT_LABELs and things like that - an extra "utility" constant. Pro: if I develop a new checker, I just add a constant or two and I instantly have a working, customized logger; (BIG) Con: extra constant value in practically every file
Not flexible enough. With other central types you can make whatever type you like it does not depend on the class or file, IT DEPENDS ON THE CONTEXT.
I think the other solution is to just keep logTypes, expect it to be huge and try to make that usable and maintainable - put it in it's own file and somehow make it foolproof in a way so that I don't forget to add my new log values to the new log checker
I think adding a new logger type is very simple. One constant + 1 boilerplate func.
Also, the question is: how much do we plan to fill up logTypes right now? Do we want to 1) go through a lot of places and add a lot of custom log types OR 2) do we do it gradually - e.g., you add what you needed (yices, cegar, whatever) and the next person who needs it elsewhere, say IC3, can add it there. I would prefer the latter - just with some really well shown / highlighted doc, so that people know that they can do this?
Doing it gradually is better cause the log types depend on the contex not the class so its not very simple to add, you have to understand that part of code. Therefore, refactoring all of it right now is like an "impossible" task.
Adding better docs is better.
This PR is barely finished I just wanted a review if the API is nice and fits theta's ecosystem and mindset. |
|
Thank you for the PR, this is something that was needed for a while now:D Levi commented above that he would like to see "new" gone from the CLI parameter descriptions. I think this is something that we should go even further with and completely avoid maintaining both a "new" and "old/legacy" logging system, and instead remove the legacy logging completely, including:
If we reach a stable new logging system that can provide everything the legacy logging did, I think there is no need to maintain the legacy parts, they would only lead to confusion. |
Also I think it would be better to arrive on one option instead of having "grep", "log" and "loglevel" on the CLI interfaces. We have proper versioning, so we don't necessarily have to stick to older CLI parameters. |
Maybe it's just nostalgia, but I would vouch to keep the current loglevel flag. :D But I agree that we should only have one flag. If it can do complex regex expressions then it can do simple ones as well, so maybe with a different syntax, but it can still express what the old levels expressed. And I agree about being able to change the flag syntax due to versioning. |
|
@AdamZsofi To implement the Legacy (old flags) I just translated them to the appropriate regex expressions for the "grep" API. |
…disable support - Replace multiple Logger classes (BaseLogger, ConsoleLogger, FileLogger, NullLogger, UniqueWarningLogger) with a single Kotlin object Logger - Add Logger.enabled.kt / Logger.disabled.kt templates for compile-time logging toggle via -PnoLogging - Make Level enum public, remove isEnabled(String) overload - Update all call sites across analysis algorithms, CLI tools, tests, and solver installers to use the new Logger API - Fix corrupted StsMddCheckerTest.java (missing block comment opener) - Remove stale bin/.gitignore files - Add Logging.md documentation
|
I finished refactoring all the logger to a singleton:
Another important thing is that I could see |
|
@KlevisImeri
I'll do a second review on this in the meantime sometime. |
There was a problem hiding this comment.
Just to make it clear: log levels are still built upon each other, i.e., init to BENCHMARK will still log error, warn, etc., right?
There was a problem hiding this comment.
I removed that, but I can add it back. I just left it as a regex string. More simple.
| @@ -0,0 +1,277 @@ | |||
| /* | |||
There was a problem hiding this comment.
This is what I was looking for to understand the logger, great! Can you maybe reference these tests as examples in the doc?
There was a problem hiding this comment.
That is a great idea.
|
|
||
| @Parameter(names = "--loglevel", description = "Detailedness of logging") | ||
| Logger.Level logLevel = Logger.Level.MAINSTEP; | ||
| @Parameter(names = "--loglevel", description = "Regex pattern for log levels (e.g. ERROR|WARN|INFO)") |
There was a problem hiding this comment.
Okay, so, connecting to my first comment, I think I understand the logger itself now.
AFAIK if you say "INFO", it will ONLY display the info level logs, nothing else above/below - that is of course necessary to be able to set the granularity, regex, etc.
But maybe we misunderstood each other: on the clis, if I say "INFO" in --loglevel, I think I still actually want "INFO|everything below INFO", as it was before the refactor. I don't want to list all the levels. This is still the most common use case, so I don't think it can change.
(Am I correct with above or did I manage to misunderstand the whole thing?)
There was a problem hiding this comment.
(This goes for all the other CLIs as well. I think some earlier reviews addressed this as well.)
There was a problem hiding this comment.
I can design such that if it says INFO i get only the "INFO|+everything below" but that means you have two user interfaces.
I mean how do you design the cli interface such that the user can ask both "INFO|+everything below" and just "INFO"?
The way maybe that it woudl be nicer is instead of calling --loglevel I woudl just call it --log. So for:
- "INFO|+everything below":
./theta --log -level INFO - "INFO":
./theta --log "INFO"
…ing and copyright
PR: Logger singleton
Read
Logging.md