digitalmars.D - std.logger
- Robert Schadek (21/21) Aug 22 2013 I'm still missing a logging facility in D and as the last attempt seam
- Johannes Pfau (11/40) Aug 22 2013 It would be nice to finally have logging in phobos.
- Robert Schadek (8/17) Aug 22 2013 I know. I did this because with the last logger, people where
- Craig Dillabaugh (7/19) Aug 22 2013 Would logWarning(), logInfo(), logError() work? You already have
- Robert Schadek (3/19) Aug 22 2013 logMessage is meant to do the actual logging. And IMO it is to much to l...
- Robert Schadek (5/7) Aug 22 2013 sry, logMessage is meant to figure out if the LogLevel of the message
- Craig Dillabaugh (10/20) Aug 22 2013 Do you really find the three extra characters a big problem.
- Craig Dillabaugh (9/34) Aug 22 2013 One other advantage of this naming convention is that when the
- Robert Schadek (8/17) Aug 22 2013 You are properly right, but ultimately I would like to write log(),
- Craig Dillabaugh (3/28) Aug 22 2013 It seems like Jacob's suggestion (if you like that) solves both
- Jacob Carlborg (10/17) Aug 22 2013 With my suggestion you can use the with-statement as well if you are
- Robert Schadek (2/10) Aug 22 2013 yes, I believe you're right, but I have not coded/tested it yet
- David Nadlinger (7/8) Aug 22 2013 They are unnecessary. If you want to make clear you are dealing
- Jonathan M Davis (7/17) Aug 22 2013 I'd oppose warning, critical, error, etc. because they're not verbs like...
- SomeDude (10/31) Aug 24 2013 OTOH, they are used in just about every logging API ever devised.
- Jonathan M Davis (7/16) Aug 24 2013 Well, we're going to have to agree to disagree on that point. Functions ...
- Robert Schadek (2/18) Aug 24 2013 luckily all log functions are called log and logf now.
- Craig Dillabaugh (15/23) Aug 22 2013 I think the two solutions are pretty close in terms of
- BS (18/18) Aug 22 2013 I hope this gets up, I've been waiting for a std.logger for a
- Jacob Carlborg (11/14) Aug 22 2013 My suggestion is you define a single function "log". This returns an
- Robert Schadek (6/14) Aug 22 2013 I like this part. But you will still need two more module level function
- ilya-stromberg (9/13) Aug 22 2013 We should avoid name conflicts as much as possible. So, I vote to
- Robert Schadek (27/28) Sep 07 2013 On 08/22/2013 05:06 PM, Johannes Pfau wrote:
- develop32 (8/38) Aug 22 2013 Why logging functions accept only a string? I would expect it to
- Jacob Carlborg (5/12) Aug 22 2013 Good point, and formatted output as well:
- evilrat (3/19) Aug 22 2013 maybe it is bad idea, but string.format can be used too.
- Robert Schadek (7/14) Aug 22 2013 I thought about that. IMO this would create very heavy template bloat,
- Johannes Pfau (7/25) Aug 22 2013 The problem is that format allocates using the GC. Functions like
- Robert Schadek (6/11) Aug 22 2013 yes, but as you said it is not simple. If it where a template the
- Johannes Pfau (14/25) Aug 22 2013 I've implemented a small logger some time ago and IIRC I couldn't come
- Robert Schadek (6/31) Aug 22 2013 What happens if this throws because of an overflow and you're only
- Piotr Szturmaj (6/8) Aug 22 2013 What about specifying log level at runtime, e.g.:
- Robert Schadek (6/14) Aug 23 2013 Any other Logger:
- Piotr Szturmaj (13/31) Aug 23 2013 I see, but isn't separate class instance for every log level a bit too
- Robert Schadek (4/25) Aug 23 2013 There isn't. Every Logger has a LogLevel, which can be changed. Every
- growler (3/3) Aug 23 2013 Is there any plan to support remote logging? This would be great
- Robert Schadek (3/6) Aug 23 2013 Not buildin, but the logger is designed to be easily extended. So if
- growler (2/11) Aug 23 2013 will do, thanks :D
- Piotr Szturmaj (22/53) Aug 23 2013 so if I have a LogLevel variable I want to use:
- Robert Schadek (7/32) Aug 23 2013 auto myLogger = new MyLogger(myLogLevel);
- Piotr Szturmaj (18/58) Aug 23 2013 So, we're at the start point. You must either create instances for every...
- Robert Schadek (29/78) Aug 23 2013 I don't see your point. Currently there are two trivial logger. An stdio
- Gambler (24/115) Aug 23 2013 Piotr brings up good very points and I would say your answers don't
- Andrei Alexandrescu (6/8) Aug 23 2013 (Just hanging this to a random comment in this thread.) I think there's
- Robert Schadek (7/12) Aug 23 2013 Yes I know, but as you said, it got abandoned. So something must have
- Andrei Alexandrescu (4/16) Aug 23 2013 Great. There was nothing wrong with it except it got no more work. I'd
- Robert Schadek (2/20) Aug 24 2013 Of course, it has to be phobos worthy.
- H. S. Teoh (7/12) Aug 23 2013 [...]
- Dicebot (3/15) Aug 25 2013 https://github.com/D-Programming-Language/phobos/pull/432
- Jose A Garcia Sancio (12/24) Sep 17 2013 The code is here:
- Artem Tarasov (3/4) Aug 22 2013 6 params to logMessage and writeMsgToLog is way too many.
- Gary Willoughby (10/11) Aug 23 2013 Just to weight in and give my four penneth. It needs to be made a
- Robert Schadek (5/14) Aug 23 2013 I do as well, but this will lead to template bloat, as many people will
- Gary Willoughby (7/12) Aug 23 2013 I don't think you can bloat a simple logger too much with
- Robert Schadek (9/15) Aug 23 2013 every log call with more than a string will be a template. My first
- Jonathan M Davis (10/12) Aug 23 2013 If __FILE__ and __LINE__ are template arguments to a logging function ra...
- Johannes Pfau (4/21) Aug 23 2013 Make the templated function a stub which redirects to a function which
- Jonathan M Davis (5/28) Aug 23 2013 Inlining will have no effect on __FILE__ and __LINE__, and it would be a...
- Johannes Pfau (12/41) Aug 23 2013 I think you misunderstood. If you write code like this:
- Robert Schadek (9/16) Aug 23 2013 I think I came up with something good looking. A regex explains it best.
- H. S. Teoh (17/32) Aug 23 2013 [...]
- Jacob Carlborg (4/7) Aug 23 2013 Won't it be just as much template bloat using "format"?
- Robert Schadek (2/7) Aug 23 2013 well yes, but log(A...)(A a) { format("...", a); } is worse ;-)
- Volcz (14/14) Sep 07 2013 I would to drop some requirements I've seen in the Java world.
I'm still missing a logging facility in D and as the last attempt seam to have stopped I want to throw in my version. After reading through the std.log thread I made my conclusions and created my own logger. People seamed to be unhappy with the naming and the way of configuration. Additionally when to throw or not to throw seamed to be an argument. My attempt is to provide a very small functional interface to logging. IMO it is impossible to fulfill all requirements a D developer can have through configuration classes and such, I designed the a abstract Logger class that can be easily implemented to one's own needs. As a quick start feature I created a Stdio- and File-Logger. If no Logger is provided to the log function a defaultLogger will be used. Docu: http://burner.github.io/phobos/phobos-prerelease/std_logger.html Pull Request: https://github.com/D-Programming-Language/phobos/pull/1500 I hope this will lead to some progress in phobos, when it comes to message logging.
Aug 22 2013
Am Thu, 22 Aug 2013 16:00:06 +0200 schrieb Robert Schadek <realburner gmx.de>:I'm still missing a logging facility in D and as the last attempt seam to have stopped I want to throw in my version. After reading through the std.log thread I made my conclusions and created my own logger. People seamed to be unhappy with the naming and the way of configuration. Additionally when to throw or not to throw seamed to be an argument. My attempt is to provide a very small functional interface to logging. IMO it is impossible to fulfill all requirements a D developer can have through configuration classes and such, I designed the a abstract Logger class that can be easily implemented to one's own needs. As a quick start feature I created a Stdio- and File-Logger. If no Logger is provided to the log function a defaultLogger will be used. Docu: http://burner.github.io/phobos/phobos-prerelease/std_logger.html Pull Request: https://github.com/D-Programming-Language/phobos/pull/1500 I hope this will lead to some progress in phobos, when it comes to message logging.It would be nice to finally have logging in phobos. Two small nit-picks: The API doesn't follow the phobos naming conventions: functions (error, fatal, ...) need to start with a lowercase letter. Same for enum members. See http://dlang.org/dstyle.html I guess the function string for writeLogMsg is fully-qualified? I'd like to see module and function split into two parts. Or fully-qualified function + module so the fully qualified function name can be sliced to strip the module name: auto fn = func[module.length .. $]
Aug 22 2013
On 08/22/2013 05:06 PM, Johannes Pfau wrote:It would be nice to finally have logging in phobos. Two small nit-picks: The API doesn't follow the phobos naming conventions: functions (error, fatal, ...) need to start with a lowercase letter. Same for enum members. See http://dlang.org/dstyle.htmlI know. I did this because with the last logger, people where complaining that log, info, warning ... where to common names. I'm very open for suggestion here. lowercase or otherwise.I guess the function string for writeLogMsg is fully-qualified? I'd like to see module and function split into two parts. Or fully-qualified function + module so the fully qualified function name can be sliced to strip the module name: auto fn = func[module.length .. $]This is what is done inside of StdIOLogger and FileLogger. I did not want to do this splitting in Logger.logMessage as the user could rewrite that to fit its need. Maybe I can add two static method that return the modulename and the function name.
Aug 22 2013
On Thursday, 22 August 2013 at 15:17:16 UTC, Robert Schadek wrote:On 08/22/2013 05:06 PM, Johannes Pfau wrote:Would logWarning(), logInfo(), logError() work? You already have a logMessage() in there. It might be a bit redundant in some instances ( Logger.logError() ), but in other cases it be clearer (eg., logError("Oh no! Something went wrong!"). CraigIt would be nice to finally have logging in phobos. Two small nit-picks: The API doesn't follow the phobos naming conventions: functions (error, fatal, ...) need to start with a lowercase letter. Same for enum members. See http://dlang.org/dstyle.htmlI know. I did this because with the last logger, people where complaining that log, info, warning ... where to common names. I'm very open for suggestion here. lowercase or otherwise.
Aug 22 2013
On 08/22/2013 05:32 PM, Craig Dillabaugh wrote:On Thursday, 22 August 2013 at 15:17:16 UTC, Robert Schadek wrote:logMessage is meant to do the actual logging. And IMO it is to much to long. But keep the ideas coming there must be a sweet spot somewhere.On 08/22/2013 05:06 PM, Johannes Pfau wrote:Would logWarning(), logInfo(), logError() work? You already have a logMessage() in there. It might be a bit redundant in some instances ( Logger.logError() ), but in other cases it be clearer (eg., logError("Oh no! Something went wrong!").It would be nice to finally have logging in phobos. Two small nit-picks: The API doesn't follow the phobos naming conventions: functions (error, fatal, ...) need to start with a lowercase letter. Same for enum members. See http://dlang.org/dstyle.htmlI know. I did this because with the last logger, people where complaining that log, info, warning ... where to common names. I'm very open for suggestion here. lowercase or otherwise.
Aug 22 2013
On 08/22/2013 05:38 PM, Robert Schadek wrote:logMessage is meant to do the actual logging. And IMO it is to much to long. But keep the ideas coming there must be a sweet spot somewhere.sry, logMessage is meant to figure out if the LogLevel of the message makes it worthy to be printed and to disable the logging via version(DisableLogger). writeLogMsg does the actual logging
Aug 22 2013
On Thursday, 22 August 2013 at 15:41:40 UTC, Robert Schadek wrote:On 08/22/2013 05:38 PM, Robert Schadek wrote:Do you really find the three extra characters a big problem. Log() vs. logLog() //OK, that is kind of ugly. Info() vs logInfo() Warning() vs logWarning() Error() vs logError() Its only three extra characters and they are all in the sweet spot on my QWERTY keyboard :o) I guess my concern would be that if you want to use camelCase and start with a lower case letter, there are not a tonne of options.logMessage is meant to do the actual logging. And IMO it is to much to long. But keep the ideas coming there must be a sweet spot somewhere.sry, logMessage is meant to figure out if the LogLevel of the message makes it worthy to be printed and to disable the logging via version(DisableLogger). writeLogMsg does the actual logging
Aug 22 2013
On Thursday, 22 August 2013 at 15:51:53 UTC, Craig Dillabaugh wrote:On Thursday, 22 August 2013 at 15:41:40 UTC, Robert Schadek wrote:One other advantage of this naming convention is that when the plain logging fuctions are used: Critical("I don't like your naming convention!"); vs. logCritical("Yeah, well yours isn't any better."); It is a bit more obvious in the 2nd case what is happening (IMO anyway, or imoAnyway).On 08/22/2013 05:38 PM, Robert Schadek wrote:Do you really find the three extra characters a big problem. Log() vs. logLog() //OK, that is kind of ugly. Info() vs logInfo() Warning() vs logWarning() Error() vs logError() Its only three extra characters and they are all in the sweet spot on my QWERTY keyboard :o) I guess my concern would be that if you want to use camelCase and start with a lower case letter, there are not a tonne of options.logMessage is meant to do the actual logging. And IMO it is to much to long. But keep the ideas coming there must be a sweet spot somewhere.sry, logMessage is meant to figure out if the LogLevel of the message makes it worthy to be printed and to disable the logging via version(DisableLogger). writeLogMsg does the actual logging
Aug 22 2013
On 08/22/2013 05:51 PM, Craig Dillabaugh wrote:Do you really find the three extra characters a big problem. Log() vs. logLog() //OK, that is kind of ugly. Info() vs logInfo() Warning() vs logWarning() Error() vs logError() Its only three extra characters and they are all in the sweet spot on my QWERTY keyboard :o) I guess my concern would be that if you want to use camelCase and start with a lower case letter, there are not a tonne of options.You are properly right, but ultimately I would like to write log(), warning(), ... but that did not fly last time. log!Warning() would also be fine but that leads to other problems. Anyway, changing to lower, logLog or something else isn't really a problem IMO when a consensus has been found.
Aug 22 2013
On Thursday, 22 August 2013 at 16:03:01 UTC, Robert Schadek wrote:On 08/22/2013 05:51 PM, Craig Dillabaugh wrote:It seems like Jacob's suggestion (if you like that) solves both of our problems.Do you really find the three extra characters a big problem. Log() vs. logLog() //OK, that is kind of ugly. Info() vs logInfo() Warning() vs logWarning() Error() vs logError() Its only three extra characters and they are all in the sweet spot on my QWERTY keyboard :o) I guess my concern would be that if you want to use camelCase and start with a lower case letter, there are not a tonne of options.You are properly right, but ultimately I would like to write log(), warning(), ... but that did not fly last time. log!Warning() would also be fine but that leads to other problems. Anyway, changing to lower, logLog or something else isn't really a problem IMO when a consensus has been found.
Aug 22 2013
On 2013-08-22 18:02, Robert Schadek wrote:You are properly right, but ultimately I would like to write log(), warning(), ... but that did not fly last time. log!Warning() would also be fine but that leads to other problems. Anyway, changing to lower, logLog or something else isn't really a problem IMO when a consensus has been found.With my suggestion you can use the with-statement as well if you are performing a lot of logging: with (log) { error("bar"); info("foo"); } -- /Jacob Carlborg
Aug 22 2013
On 08/22/2013 06:17 PM, Jacob Carlborg wrote:On 2013-08-22 18:02, Robert Schadek wrote: With my suggestion you can use the with-statement as well if you are performing a lot of logging: with (log) { error("bar"); info("foo"); }yes, I believe you're right, but I have not coded/tested it yet
Aug 22 2013
On Thursday, 22 August 2013 at 15:51:53 UTC, Craig Dillabaugh wrote:Do you really find the three extra characters a big problem.They are unnecessary. If you want to make clear you are dealing with logging, you can just write something along the lines of: import log = std.logger; log.error("123"); David
Aug 22 2013
On Thursday, August 22, 2013 23:36:48 David Nadlinger wrote:On Thursday, 22 August 2013 at 15:51:53 UTC, Craig Dillabaugh wrote:I'd oppose warning, critical, error, etc. because they're not verbs like functions are supposed to be. It's variables or properties which are nouns. So, while I agree that the module system makes it so that the name clashes shouldn't be a big deal, I disagree with the names anyway and would still prefer logWarning to warning. - Jonathan M DavisDo you really find the three extra characters a big problem.They are unnecessary. If you want to make clear you are dealing with logging, you can just write something along the lines of: import log = std.logger; log.error("123");
Aug 22 2013
On Thursday, 22 August 2013 at 22:01:09 UTC, Jonathan M Davis wrote:On Thursday, August 22, 2013 23:36:48 David Nadlinger wrote:OTOH, they are used in just about every logging API ever devised. Everybody knows what they mean. I just don't see the need to reinvent these words and make them longer by adding log. I seriously hate it. It clutters code (once you've read your thousand's log instruction, it hurts), adds ugly and useless redundancy and nothing else to its understanding. This alone is far worse than not using verbs.On Thursday, 22 August 2013 at 15:51:53 UTC, Craig Dillabaugh wrote:I'd oppose warning, critical, error, etc. because they're not verbs like functions are supposed to be. It's variables or properties which are nouns. So, while I agree that the module system makes it so that the name clashes shouldn't be a big deal, I disagree with the names anyway and would still prefer logWarning to warning. - Jonathan M DavisDo you really find the three extra characters a big problem.They are unnecessary. If you want to make clear you are dealing with logging, you can just write something along the lines of: import log = std.logger; log.error("123");
Aug 24 2013
On Saturday, August 24, 2013 16:49:24 SomeDude wrote:OTOH, they are used in just about every logging API ever devised. Everybody knows what they mean. I just don't see the need to reinvent these words and make them longer by adding log. I seriously hate it. It clutters code (once you've read your thousand's log instruction, it hurts), adds ugly and useless redundancy and nothing else to its understanding. This alone is far worse than not using verbs.Well, we're going to have to agree to disagree on that point. Functions are supposed to be verbs. They're only nouns if they're properties, in which case, they're emulating variables, which are nouns. And I'd consider following the proper naming conventions like that to be far more important than saving a few characters. - Jonathan M Davis
Aug 24 2013
On 08/24/2013 08:01 PM, Jonathan M Davis wrote:On Saturday, August 24, 2013 16:49:24 SomeDude wrote:luckily all log functions are called log and logf now.OTOH, they are used in just about every logging API ever devised. Everybody knows what they mean. I just don't see the need to reinvent these words and make them longer by adding log. I seriously hate it. It clutters code (once you've read your thousand's log instruction, it hurts), adds ugly and useless redundancy and nothing else to its understanding. This alone is far worse than not using verbs.Well, we're going to have to agree to disagree on that point. Functions are supposed to be verbs. They're only nouns if they're properties, in which case, they're emulating variables, which are nouns. And I'd consider following the proper naming conventions like that to be far more important than saving a few characters. - Jonathan M Davis
Aug 24 2013
On Thursday, 22 August 2013 at 21:36:50 UTC, David Nadlinger wrote:On Thursday, 22 August 2013 at 15:51:53 UTC, Craig Dillabaugh wrote:I think the two solutions are pretty close in terms of readability. Of course the solution here uses convention to ensure clarity in what the log functions are doing, while logError() enforces clarity. I could do: import px482374203 = std.logger; .... //much later px482374203.error("What the heck is this!"); Not that I would ever do that ... Also just to be nit-picky you are typing 4 extra characters which is 25% worse than my suggestion :o) [ In fairness having to use the shift key to type logError() likely makes log.error() just a bit easier to type.]Do you really find the three extra characters a big problem.They are unnecessary. If you want to make clear you are dealing with logging, you can just write something along the lines of: import log = std.logger; log.error("123"); David
Aug 22 2013
I hope this gets up, I've been waiting for a std.logger for a while. My custom one works fine but it's extra sideline code to compile, maintain and lug around. As for naming, I like the following log.whisper("low priority log message") log.say("default log level"); log.shout("Warning level"); log.scream("**ERROR**"); :D To be honest I don't really care about the naming, but if pressed I'd go for log("default") log.warn("a warning") log.error("an error") ...or something similar. I just find it easier to read than logWarning, logError etc. /BS
Aug 22 2013
On 2013-08-22 17:17, Robert Schadek wrote:I know. I did this because with the last logger, people where complaining that log, info, warning ... where to common names. I'm very open for suggestion here. lowercase or otherwise.My suggestion is you define a single function "log". This returns an instance of the current/default logger. The logger, be it a struct or class, have one method for each logging level. The default logging level would use opCall, resulting in this API: log("asd"); // log with default level log.warning("foo"); // log with warning level log.error("asd"); // And so on. Then you would only have one function at the module level. -- /Jacob Carlborg
Aug 22 2013
On 08/22/2013 05:59 PM, Jacob Carlborg wrote:My suggestion is you define a single function "log". This returns an instance of the current/default logger. The logger, be it a struct or class, have one method for each logging level. The default logging level would use opCall, resulting in this API: log("asd"); // log with default level log.warning("foo"); // log with warning level log.error("asd"); // And so on. Then you would only have one function at the module level.I like this part. But you will still need two more module level function to set and get the global LogLevel. And log would have to return by ref to assign a new defaultLogger. But still, I like that very much, even though this is still in conflict with std.math.log.
Aug 22 2013
On Thursday, 22 August 2013 at 17:09:17 UTC, Robert Schadek wrote:On 08/22/2013 05:59 PM, Jacob Carlborg wrote: But still, I like that very much, even though this is still in conflict with std.math.log.We should avoid name conflicts as much as possible. So, I vote to the Craig Dillabaugh's idea: logLog() //OK, that is kind of ugly. logInfo() logWarning() logError() Note that we can use logDefault(), not logLog(). I think it will be better.
Aug 22 2013
On 08/22/2013 05:06 PM, Johannes Pfau wrote: I'm getting wired auto-tester erros setting up remote topull -> https://github.com/burner/phobos.git fetching contents of https://github.com/burner/phobos.gitFrom https://github.com/burner/phobos* [new branch] 10472 -> topull/10472 * [new branch] 2.061 -> topull/2.061 * [new branch] bigintpure -> topull/bigintpure * [new branch] candidate -> topull/candidate * [new branch] convpure -> topull/convpure * [new branch] deque -> topull/deque * [new branch] devel -> topull/devel * [new branch] gh-pages -> topull/gh-pages * [new branch] indexOfIdx -> topull/indexOfIdx * [new branch] lastIndexOf -> topull/lastIndexOf * [new branch] logger -> topull/logger * [new branch] master -> topull/master * [new branch] phobos-1.x -> topull/phobos-1.x * [new branch] staging -> topull/staging * [new branch] website -> topull/website merging topull/logger error: Your local changes to the following files would be overwritten by merge: win64.mak Please, commit your changes or stash them before you can merge. Aborting Updating e723325..621af63 from the error message I would say somebody did modify the win64.mak on the test machine without committing it?
Sep 07 2013
On Thursday, 22 August 2013 at 14:13:29 UTC, Robert Schadek wrote:I'm still missing a logging facility in D and as the last attempt seam to have stopped I want to throw in my version. After reading through the std.log thread I made my conclusions and created my own logger. People seamed to be unhappy with the naming and the way of configuration. Additionally when to throw or not to throw seamed to be an argument. My attempt is to provide a very small functional interface to logging. IMO it is impossible to fulfill all requirements a D developer can have through configuration classes and such, I designed the a abstract Logger class that can be easily implemented to one's own needs. As a quick start feature I created a Stdio- and File-Logger. If no Logger is provided to the log function a defaultLogger will be used. Docu: http://burner.github.io/phobos/phobos-prerelease/std_logger.html Pull Request: https://github.com/D-Programming-Language/phobos/pull/1500 I hope this will lead to some progress in phobos, when it comes to message logging.Why logging functions accept only a string? I would expect it to behave as std.stdio with its variadic parameters. It would be more straightforward to write logging code: log("Moving ", data, " to ", destination); Where 'data' and 'destination' are any variables. I use such setup in my projects and it helps greatly to identify what went wrong when not using a debugger.
Aug 22 2013
On 2013-08-22 18:01, develop32 wrote:Why logging functions accept only a string? I would expect it to behave as std.stdio with its variadic parameters. It would be more straightforward to write logging code: log("Moving ", data, " to ", destination); Where 'data' and 'destination' are any variables. I use such setup in my projects and it helps greatly to identify what went wrong when not using a debugger.Good point, and formatted output as well: logf("Moving % to %", data, destination); -- /Jacob Carlborg
Aug 22 2013
On Thursday, 22 August 2013 at 16:16:37 UTC, Jacob Carlborg wrote:On 2013-08-22 18:01, develop32 wrote:maybe it is bad idea, but string.format can be used too. log(format("Moving %s to %s", data, destination);Why logging functions accept only a string? I would expect it to behave as std.stdio with its variadic parameters. It would be more straightforward to write logging code: log("Moving ", data, " to ", destination); Where 'data' and 'destination' are any variables. I use such setup in my projects and it helps greatly to identify what went wrong when not using a debugger.Good point, and formatted output as well: logf("Moving % to %", data, destination);
Aug 22 2013
On 08/22/2013 06:01 PM, develop32 wrote:Why logging functions accept only a string? I would expect it to behave as std.stdio with its variadic parameters. It would be more straightforward to write logging code: log("Moving ", data, " to ", destination); Where 'data' and 'destination' are any variables. I use such setup in my projects and it helps greatly to identify what went wrong when not using a debugger.I thought about that. IMO this would create very heavy template bloat, because you would also have to pass __LINE__, __FUNCTION__ as template arguments. Whats so wrong with log("%s %s %s %s".format("Moving", "data", "to", destination)); This way you don't have to remember to place the spaces left and right.
Aug 22 2013
Am Thu, 22 Aug 2013 19:13:05 +0200 schrieb Robert Schadek <realburner gmx.de>:On 08/22/2013 06:01 PM, develop32 wrote:The problem is that format allocates using the GC. Functions like writefln can be much more efficient so if the backend is a FileLogger it could take advantage of that. But IIRC it's not simple to implement this 'forwarding' with classes / interfaces as you'll need templated functions...Why logging functions accept only a string? I would expect it to behave as std.stdio with its variadic parameters. It would be more straightforward to write logging code: log("Moving ", data, " to ", destination); Where 'data' and 'destination' are any variables. I use such setup in my projects and it helps greatly to identify what went wrong when not using a debugger.I thought about that. IMO this would create very heavy template bloat, because you would also have to pass __LINE__, __FUNCTION__ as template arguments. Whats so wrong with log("%s %s %s %s".format("Moving", "data", "to", destination)); This way you don't have to remember to place the spaces left and right.
Aug 22 2013
On 08/22/2013 07:48 PM, Johannes Pfau wrote:The problem is that format allocates using the GC. Functions like writefln can be much more efficient so if the backend is a FileLogger it could take advantage of that. But IIRC it's not simple to implement this 'forwarding' with classes / interfaces as you'll need templated functions...yes, but as you said it is not simple. If it where a template the assignable default logger concept would not work, as it would instantiate the template of the base class. I don't think that this is possible (plz proof me wrong). IMO the default logger concept is more important.
Aug 22 2013
Am Thu, 22 Aug 2013 20:04:16 +0200 schrieb Robert Schadek <realburner gmx.de>:On 08/22/2013 07:48 PM, Johannes Pfau wrote:I've implemented a small logger some time ago and IIRC I couldn't come up with a satisfying solution. The last std.log proposal made a compromise to deal with this: It accepted formatted log input but it did call sformat internally before passing it to the Logger implementation. The benefit of this was that it could reuse the same buffer. In (pseudo)code: void logf(Args...)(string fmt, Args args) { ubyte[BUFSIZE] buffer; _logger.log(sformat(buffer, fmt, args)); }The problem is that format allocates using the GC. Functions like writefln can be much more efficient so if the backend is a FileLogger it could take advantage of that. But IIRC it's not simple to implement this 'forwarding' with classes / interfaces as you'll need templated functions...yes, but as you said it is not simple. If it where a template the assignable default logger concept would not work, as it would instantiate the template of the base class. I don't think that this is possible (plz proof me wrong). IMO the default logger concept is more important.
Aug 22 2013
On 08/22/2013 08:17 PM, Johannes Pfau wrote:Am Thu, 22 Aug 2013 20:04:16 +0200 schrieb Robert Schadek <realburner gmx.de>:What happens if this throws because of an overflow and you're only indirectly responsable for the call to logf? I would rather pass my own static string buffer to log if I fear performance problems, than to hope that the buffer in logf is big enough.On 08/22/2013 07:48 PM, Johannes Pfau wrote:I've implemented a small logger some time ago and IIRC I couldn't come up with a satisfying solution. The last std.log proposal made a compromise to deal with this: It accepted formatted log input but it did call sformat internally before passing it to the Logger implementation. The benefit of this was that it could reuse the same buffer. In (pseudo)code: void logf(Args...)(string fmt, Args args) { ubyte[BUFSIZE] buffer; _logger.log(sformat(buffer, fmt, args)); }The problem is that format allocates using the GC. Functions like writefln can be much more efficient so if the backend is a FileLogger it could take advantage of that. But IIRC it's not simple to implement this 'forwarding' with classes / interfaces as you'll need templated functions...yes, but as you said it is not simple. If it where a template the assignable default logger concept would not work, as it would instantiate the template of the base class. I don't think that this is possible (plz proof me wrong). IMO the default logger concept is more important.
Aug 22 2013
W dniu 22.08.2013 16:00, Robert Schadek pisze:Docu: http://burner.github.io/phobos/phobos-prerelease/std_logger.htmlWhat about specifying log level at runtime, e.g.: // set by the user at runtime LogLevel userLogLevelForX; log(userLogLevelForX, "X"); ?
Aug 22 2013
On 08/23/2013 02:07 AM, Piotr Szturmaj wrote:W dniu 22.08.2013 16:00, Robert Schadek pisze:Any other Logger: auto myCoolLogger = new XXXXLogger(); myCoolLogger.logLevel = LogLevel.Critical; For the default Logger: log.logLevel = LogLevel.Info;Docu: http://burner.github.io/phobos/phobos-prerelease/std_logger.htmlWhat about specifying log level at runtime, e.g.: // set by the user at runtime LogLevel userLogLevelForX; log(userLogLevelForX, "X"); ?
Aug 23 2013
W dniu 23.08.2013 09:44, Robert Schadek pisze:On 08/23/2013 02:07 AM, Piotr Szturmaj wrote:I see, but isn't separate class instance for every log level a bit too much? Setting log level before calling log() isn't (IMHO) good either (think of multi-threaded logging). My opinion is that LogLevel should not be encapsulated within Logger class. Instead function overloading should be used (again IMO): void log(string message); void log(LogLevel level, string message); So having separate classes for different loggers (sinks) is very nice, but LogLevel should be specifiable for each message, no matter which Logger class is used. Then, each _compile-time_ specifiers like .Warning() or .Error() should be just a syntactic sugar over log().W dniu 22.08.2013 16:00, Robert Schadek pisze:Any other Logger: auto myCoolLogger = new XXXXLogger(); myCoolLogger.logLevel = LogLevel.Critical; For the default Logger: log.logLevel = LogLevel.Info;Docu: http://burner.github.io/phobos/phobos-prerelease/std_logger.htmlWhat about specifying log level at runtime, e.g.: // set by the user at runtime LogLevel userLogLevelForX; log(userLogLevelForX, "X"); ?
Aug 23 2013
On 08/23/2013 10:30 AM, Piotr Szturmaj wrote:There isn't. Every Logger has a LogLevel, which can be changed. Every log message also has a LogLevel hence .info() .error() ...I see, but isn't separate class instance for every log level a bit too much? Setting log level before calling log() isn't (IMHO) good either (think of multi-threaded logging).?Any other Logger: auto myCoolLogger = new XXXXLogger(); myCoolLogger.logLevel = LogLevel.Critical; For the default Logger: log.logLevel = LogLevel.Info;My opinion is that LogLevel should not be encapsulated within Logger class. Instead function overloading should be used (again IMO): void log(string message); void log(LogLevel level, string message); So having separate classes for different loggers (sinks) is very nice, but LogLevel should be specifiable for each message, no matter which Logger class is used.It is.Then, each _compile-time_ specifiers like .Warning() or .Error() should be just a syntactic sugar over log().
Aug 23 2013
Is there any plan to support remote logging? This would be great for embedded stuff we're playing with. G.
Aug 23 2013
On 08/23/2013 12:00 PM, growler wrote:Is there any plan to support remote logging? This would be great for embedded stuff we're playing with. G.Not buildin, but the logger is designed to be easily extended. So if needed, roll your own.
Aug 23 2013
On Friday, 23 August 2013 at 10:09:42 UTC, Robert Schadek wrote:On 08/23/2013 12:00 PM, growler wrote:will do, thanks :DIs there any plan to support remote logging? This would be great for embedded stuff we're playing with. G.Not buildin, but the logger is designed to be easily extended. So if needed, roll your own.
Aug 23 2013
W dniu 23.08.2013 11:01, Robert Schadek pisze:On 08/23/2013 10:30 AM, Piotr Szturmaj wrote:so if I have a LogLevel variable I want to use: LogLevel myLogLevel; I need to write this: switch (myLogLevel) { case LogLevel.Info: log.Info("..."); break; case LogLevel.Warning: log.Warning("..."); break; case LogLevel.Error: log.Error("..."); break; case LogLevel.Critical: log.Critical("..."); break; case LogLevel.Fatal: log.Fatal("..."); break; } #alternative 2 log.logLevel = myLogLevel; // not thread-safe (shared state) log("..."); I mean sure, it is possible to specify LogLevel for each message, but only at compile time (by the use of function names .Info, .Error, etc.). This is not what I meant in my previous post. I rather meant the ability to specify LogLevel using a runtime variable.There isn't. Every Logger has a LogLevel, which can be changed. Every log message also has a LogLevel hence .info() .error() ...I see, but isn't separate class instance for every log level a bit too much? Setting log level before calling log() isn't (IMHO) good either (think of multi-threaded logging).?Any other Logger: auto myCoolLogger = new XXXXLogger(); myCoolLogger.logLevel = LogLevel.Critical; For the default Logger: log.logLevel = LogLevel.Info;My opinion is that LogLevel should not be encapsulated within Logger class. Instead function overloading should be used (again IMO): void log(string message); void log(LogLevel level, string message); So having separate classes for different loggers (sinks) is very nice, but LogLevel should be specifiable for each message, no matter which Logger class is used.It is.Just thought that the ability to add user defined log levels may be useful too.Then, each _compile-time_ specifiers like .Warning() or .Error() should be just a syntactic sugar over log().
Aug 23 2013
On 08/23/2013 01:10 PM, Piotr Szturmaj wrote:so if I have a LogLevel variable I want to use: LogLevel myLogLevel; I need to write this: switch (myLogLevel) { case LogLevel.Info: log.Info("..."); break; case LogLevel.Warning: log.Warning("..."); break; case LogLevel.Error: log.Error("..."); break; case LogLevel.Critical: log.Critical("..."); break; case LogLevel.Fatal: log.Fatal("..."); break; } #alternative 2 log.logLevel = myLogLevel; // not thread-safe (shared state) log("...");the default logger is not shared. so no thread problems.I mean sure, it is possible to specify LogLevel for each message, but only at compile time (by the use of function names .Info, .Error, etc.). This is not what I meant in my previous post. I rather meant the ability to specify LogLevel using a runtime variable.auto myLogger = new MyLogger(myLogLevel); mylogger("my log msg");You can implement the abstract logger class and create new log functions, but the design is intended to simple and user defined log level makes it complex.Just thought that the ability to add user defined log levels may be useful too.Then, each _compile-time_ specifiers like .Warning() or .Error() should be just a syntactic sugar over log().
Aug 23 2013
W dniu 23.08.2013 14:16, Robert Schadek pisze:On 08/23/2013 01:10 PM, Piotr Szturmaj wrote:But the problems remain with non-default loggers?so if I have a LogLevel variable I want to use: LogLevel myLogLevel; I need to write this: switch (myLogLevel) { case LogLevel.Info: log.Info("..."); break; case LogLevel.Warning: log.Warning("..."); break; case LogLevel.Error: log.Error("..."); break; case LogLevel.Critical: log.Critical("..."); break; case LogLevel.Fatal: log.Fatal("..."); break; } #alternative 2 log.logLevel = myLogLevel; // not thread-safe (shared state) log("...");the default logger is not shared. so no thread problems.So, we're at the start point. You must either create instances for every log level (and for every logger class) or set a log level before calling the log() - and this is not thread safe for custom loggers. This also doesn't look as a good design: auto myLogger = new MyLogger(myLogLevel); myLogger("my log msg"); myLogger.logLevel = anotherMyLogLevel; myLogger("another log msg"); myLogger.logLevel = yetAnotherMyLogLevel; myLogger("yet another log msg"); Why encapsulate a logLevel which is immediately used in the function? Why store it in a class? It should be a function parameter instead. Don't get me wrong. I just want to help you. I think that default logger concept should be separated to default logger and default log level (default log level should be independent from default logger)I mean sure, it is possible to specify LogLevel for each message, but only at compile time (by the use of function names .Info, .Error, etc.). This is not what I meant in my previous post. I rather meant the ability to specify LogLevel using a runtime variable.auto myLogger = new MyLogger(myLogLevel); mylogger("my log msg");You can implement the abstract logger class and create new log functions, but the design is intended to simple and user defined log level makes it complex.Just thought that the ability to add user defined log levels may be useful too.Then, each _compile-time_ specifiers like .Warning() or .Error() should be just a syntactic sugar over log().
Aug 23 2013
On 08/23/2013 02:56 PM, Piotr Szturmaj wrote:W dniu 23.08.2013 14:16, Robert Schadek pisze:I don't see your point. Currently there are two trivial logger. An stdio and a file logger. Both are thread local. There are only these two, because I believe that you cannot create a logging library that fulfills everybody requirements and trying will lead to a logger library nobody can use anymore. So I took the opposite direction and made it simple merely defining a common interface to make logging to defined types of loggers uniform. So if you need a logger that is thread safe. Please created on and use it.On 08/23/2013 01:10 PM, Piotr Szturmaj wrote:But the problems remain with non-default loggers?so if I have a LogLevel variable I want to use: LogLevel myLogLevel; I need to write this: switch (myLogLevel) { case LogLevel.Info: log.Info("..."); break; case LogLevel.Warning: log.Warning("..."); break; case LogLevel.Error: log.Error("..."); break; case LogLevel.Critical: log.Critical("..."); break; case LogLevel.Fatal: log.Fatal("..."); break; } #alternative 2 log.logLevel = myLogLevel; // not thread-safe (shared state) log("...");the default logger is not shared. so no thread problems.If the LogLevel you are using are not const and are computed during the lifetime of the program. Than yes, that is the way you have to use it. But if anotherMyLogLevel and yetAnotherMyLogLevel are mere const, why not write myLogger.warning("...."); myLogger.error("...")?So, we're at the start point. You must either create instances for every log level (and for every logger class) or set a log level before calling the log() - and this is not thread safe for custom loggers. This also doesn't look as a good design: auto myLogger = new MyLogger(myLogLevel); myLogger("my log msg"); myLogger.logLevel = anotherMyLogLevel; myLogger("another log msg"); myLogger.logLevel = yetAnotherMyLogLevel; myLogger("yet another log msg");I mean sure, it is possible to specify LogLevel for each message, but only at compile time (by the use of function names .Info, .Error, etc.). This is not what I meant in my previous post. I rather meant the ability to specify LogLevel using a runtime variable.auto myLogger = new MyLogger(myLogLevel); mylogger("my log msg");Why encapsulate a logLevel which is immediately used in the function? Why store it in a class? It should be a function parameter instead.I'm not sure if I understand your first sentence! Having a LogLevel stored in a logger allows to disable the logging of some of the messages send to a specific logger. Example: auto myLogger = new Logger(); myLogger.warning("Something is fishy"); myLogger.warning("Something else is fishy"); next round I want to disable warning messages logged by myLogger. I don't want to touch all the .warning("..") lines. I want to write myLogger.logLevel = LogLevel.Fatal; and disable all warning messages this way.Don't get me wrong. I just want to help you. I think that default logger concept should be separated to default logger and default log level (default log level should be independent from default logger)It is separated! LogManager.globalLogLevel = LogLevel.XXXXX; sets the global LogLevel. The defaultLogger is just another logger which can be found at a special place.
Aug 23 2013
On 8/23/2013 9:48 AM, Robert Schadek wrote:On 08/23/2013 02:56 PM, Piotr Szturmaj wrote:Piotr brings up good very points and I would say your answers don't fully address them. Why should there be 5 differently named methods for something that does *the same thing* except for logging level? What is the advantage over having just one with level passed as a parameter? Also, if I understand it correctly, the class has a method that will log *the same message* at different levels based on some centralized configuration. That doesn't sound like a good idea. Severity of an error depends on what it is. It doesn't sound right to change it based on some centralized config setting in an unrelated class. I.e. if something is a fatal error, it should always be explicitly, obviously fatal. Changing that *should* require an explicit change at the place where the error is logged. Frankly, I would not allow changing loggers LogLevel after initialization either. There is simply no good reason to do that and sound so would lead to really annoying issues when analyzing code. (See PHP's awful operator.) Lastly, I think what Piotr meant by "separated" is that there is a common need to separate log *collector* (which should be as standard as possible) and log *emitters* (which would do different things for the same message, like sending emails, writing to files, outputting the yellow screen of death, etc). LogLevel should be a property of log emitters. That's a very, very common need. You want to write every single message to a file, but you only want to get fatal errors via email.W dniu 23.08.2013 14:16, Robert Schadek pisze:I don't see your point. Currently there are two trivial logger. An stdio and a file logger. Both are thread local. There are only these two, because I believe that you cannot create a logging library that fulfills everybody requirements and trying will lead to a logger library nobody can use anymore. So I took the opposite direction and made it simple merely defining a common interface to make logging to defined types of loggers uniform. So if you need a logger that is thread safe. Please created on and use it.On 08/23/2013 01:10 PM, Piotr Szturmaj wrote:But the problems remain with non-default loggers?so if I have a LogLevel variable I want to use: LogLevel myLogLevel; I need to write this: switch (myLogLevel) { case LogLevel.Info: log.Info("..."); break; case LogLevel.Warning: log.Warning("..."); break; case LogLevel.Error: log.Error("..."); break; case LogLevel.Critical: log.Critical("..."); break; case LogLevel.Fatal: log.Fatal("..."); break; } #alternative 2 log.logLevel = myLogLevel; // not thread-safe (shared state) log("...");the default logger is not shared. so no thread problems.If the LogLevel you are using are not const and are computed during the lifetime of the program. Than yes, that is the way you have to use it. But if anotherMyLogLevel and yetAnotherMyLogLevel are mere const, why not write myLogger.warning("...."); myLogger.error("...")?So, we're at the start point. You must either create instances for every log level (and for every logger class) or set a log level before calling the log() - and this is not thread safe for custom loggers. This also doesn't look as a good design: auto myLogger = new MyLogger(myLogLevel); myLogger("my log msg"); myLogger.logLevel = anotherMyLogLevel; myLogger("another log msg"); myLogger.logLevel = yetAnotherMyLogLevel; myLogger("yet another log msg");I mean sure, it is possible to specify LogLevel for each message, but only at compile time (by the use of function names .Info, .Error, etc.). This is not what I meant in my previous post. I rather meant the ability to specify LogLevel using a runtime variable.auto myLogger = new MyLogger(myLogLevel); mylogger("my log msg");Why encapsulate a logLevel which is immediately used in the function? Why store it in a class? It should be a function parameter instead.I'm not sure if I understand your first sentence! Having a LogLevel stored in a logger allows to disable the logging of some of the messages send to a specific logger. Example: auto myLogger = new Logger(); myLogger.warning("Something is fishy"); myLogger.warning("Something else is fishy"); next round I want to disable warning messages logged by myLogger. I don't want to touch all the .warning("..") lines. I want to write myLogger.logLevel = LogLevel.Fatal; and disable all warning messages this way.Don't get me wrong. I just want to help you. I think that default logger concept should be separated to default logger and default log level (default log level should be independent from default logger)It is separated! LogManager.globalLogLevel = LogLevel.XXXXX; sets the global LogLevel. The defaultLogger is just another logger which can be found at a special place.
Aug 23 2013
On 8/23/13 4:10 AM, Piotr Szturmaj wrote:Just thought that the ability to add user defined log levels may be useful too.(Just hanging this to a random comment in this thread.) I think there's some pretty good work on logging by myself and another poster (Jose?) that has since gone abandoned. It included some nice approach to conditional logging and had both compile-time and run-time configurability. Andrei
Aug 23 2013
On 08/23/2013 09:41 PM, Andrei Alexandrescu wrote:(Just hanging this to a random comment in this thread.) I think there's some pretty good work on logging by myself and another poster (Jose?) that has since gone abandoned. It included some nice approach to conditional logging and had both compile-time and run-time configurabilityYes I know, but as you said, it got abandoned. So something must have been wrong. I rather start something fresh and argue about whats wrong with that, than argue whats wrong with something old that has been already argued about and got abandoned.
Aug 23 2013
On 8/23/13 1:10 PM, Robert Schadek wrote:On 08/23/2013 09:41 PM, Andrei Alexandrescu wrote:Great. There was nothing wrong with it except it got no more work. I'd expect a new framework to be at least as good if not better. Andrei(Just hanging this to a random comment in this thread.) I think there's some pretty good work on logging by myself and another poster (Jose?) that has since gone abandoned. It included some nice approach to conditional logging and had both compile-time and run-time configurabilityYes I know, but as you said, it got abandoned. So something must have been wrong. I rather start something fresh and argue about whats wrong with that, than argue whats wrong with something old that has been already argued about and got abandoned.
Aug 23 2013
On 08/23/2013 11:49 PM, Andrei Alexandrescu wrote:On 8/23/13 1:10 PM, Robert Schadek wrote:Of course, it has to be phobos worthy.On 08/23/2013 09:41 PM, Andrei Alexandrescu wrote:Great. There was nothing wrong with it except it got no more work. I'd expect a new framework to be at least as good if not better. Andrei(Just hanging this to a random comment in this thread.) I think there's some pretty good work on logging by myself and another poster (Jose?) that has since gone abandoned. It included some nice approach to conditional logging and had both compile-time and run-time configurabilityYes I know, but as you said, it got abandoned. So something must have been wrong. I rather start something fresh and argue about whats wrong with that, than argue whats wrong with something old that has been already argued about and got abandoned.
Aug 24 2013
On Fri, Aug 23, 2013 at 12:41:45PM -0700, Andrei Alexandrescu wrote: [...](Just hanging this to a random comment in this thread.) I think there's some pretty good work on logging by myself and another poster (Jose?) that has since gone abandoned. It included some nice approach to conditional logging and had both compile-time and run-time configurability.[...] Where's the code? T -- What doesn't kill me makes me stranger.
Aug 23 2013
On Friday, 23 August 2013 at 20:11:38 UTC, H. S. Teoh wrote:On Fri, Aug 23, 2013 at 12:41:45PM -0700, Andrei Alexandrescu wrote: [...]https://github.com/D-Programming-Language/phobos/pull/432 (got from http://wiki.dlang.org/Review_Queue)(Just hanging this to a random comment in this thread.) I think there's some pretty good work on logging by myself and another poster (Jose?) that has since gone abandoned. It included some nice approach to conditional logging and had both compile-time and run-time configurability.[...] Where's the code? T
Aug 25 2013
On Friday, 23 August 2013 at 20:11:38 UTC, H. S. Teoh wrote:On Fri, Aug 23, 2013 at 12:41:45PM -0700, Andrei Alexandrescu wrote: [...]The code is here: https://github.com/jsancio/log.d/blob/master/src/log.d For what it is worth, there was a lot of thought and effort that was put into the design, implementation and testing of it. If you are interested in the design goals of the std.log library then my recommendation is to learn about glog (http://google-glog.googlecode.com/svn/trunk/doc/glog.html). If the community decides that they like those design principles then I highly recommend you continue where std.log left off. Thanks, -Jose(Just hanging this to a random comment in this thread.) I think there's some pretty good work on logging by myself and another poster (Jose?) that has since gone abandoned. It included some nice approach to conditional logging and had both compile-time and run-time configurability.[...] Where's the code? T
Sep 17 2013
http://burner.github.io/phobos/phobos-prerelease/std_logger.html6 params to logMessage and writeMsgToLog is way too many. First four of them should be merged into a single struct representing the location.
Aug 22 2013
On Thursday, 22 August 2013 at 14:13:29 UTC, Robert Schadek wrote:lots..Just to weight in and give my four penneth. It needs to be made a little more flexible in the formats it produces (syslog?) and the input it takes. e.g. i've just finished a nice logger for work and it's main usage is like this: auto logger = new Logger("file"); logger.info("device id: %s", device.id); I like the formatting that sprintf gives. Also behind the scenes everything is nicely abstract and uses the same method for output only the options change.
Aug 23 2013
On 08/23/2013 06:28 PM, Gary Willoughby wrote:On Thursday, 22 August 2013 at 14:13:29 UTC, Robert Schadek wrote:Ask if you are allowed to put it into phobos.lots..Just to weight in and give my four penneth. It needs to be made a little more flexible in the formats it produces (syslog?) and the input it takes. e.g. i've just finished a nice logger for work and it's main usage is like this:auto logger = new Logger("file"); logger.info("device id: %s", device.id); I like the formatting that sprintf gives.I do as well, but this will lead to template bloat, as many people will tell you, and log("device id: %s".format(device.id)); is not so bad.
Aug 23 2013
On Friday, 23 August 2013 at 16:49:00 UTC, Robert Schadek wrote:I don't think you can bloat a simple logger too much with templates. It's a pretty simple framework. The problem is that people rarely want to log only strings and not supporting other types will lead to this: logger.info(format("Device id: %s"), device.id); as i found when i started logging stuff. yuk!I like the formatting that sprintf gives.I do as well, but this will lead to template bloat, as many people will tell you, and log("device id: %s".format(device.id)); is not so bad.
Aug 23 2013
On 08/23/2013 07:21 PM, Gary Willoughby wrote:I don't think you can bloat a simple logger too much with templates. It's a pretty simple framework.every log call with more than a string will be a template. My first private logger version was like this. After reading the last logger thread and other stuff, template bloat seams to be an important issue. I will change some stuff tonight and will also make printf style logging a default. But if anyone screams template bloat in this thread, I expect you to hunt him down!The problem is that people rarely want to log only strings and not supporting other types will lead to this: logger.info(format("Device id: %s"), device.id); as i found when i started logging stuff. yuk!my version looked prettier!
Aug 23 2013
On Friday, August 23, 2013 19:21:33 Gary Willoughby wrote:I don't think you can bloat a simple logger too much with templates. It's a pretty simple framework.If __FILE__ and __LINE__ are template arguments to a logging function rather than function arguments (and you can't make __FILE__ and __LINE__ default function arguments if the function is variadic as it would have to be to support format strings), then you get a new template instantation every single time that you call the function, unless you call it more than once on the same line (which you're unlikely to ever do). I want to think that there's a way to handle this if you get clever, but I can't think of a clever way to get around the problem at the moment. - Jonathan M Davis
Aug 23 2013
Am Fri, 23 Aug 2013 15:16:05 -0400 schrieb "Jonathan M Davis" <jmdavisProg gmx.com>:On Friday, August 23, 2013 19:21:33 Gary Willoughby wrote:Make the templated function a stub which redirects to a function which uses normal function arguments and rely on inlining?I don't think you can bloat a simple logger too much with templates. It's a pretty simple framework.If __FILE__ and __LINE__ are template arguments to a logging function rather than function arguments (and you can't make __FILE__ and __LINE__ default function arguments if the function is variadic as it would have to be to support format strings), then you get a new template instantation every single time that you call the function, unless you call it more than once on the same line (which you're unlikely to ever do). I want to think that there's a way to handle this if you get clever, but I can't think of a clever way to get around the problem at the moment. - Jonathan M Davis
Aug 23 2013
On Friday, August 23, 2013 21:47:44 Johannes Pfau wrote:Am Fri, 23 Aug 2013 15:16:05 -0400 schrieb "Jonathan M Davis" <jmdavisProg gmx.com>:Inlining will have no effect on __FILE__ and __LINE__, and it would be a bug if it did, because they're supposed to give the file and line number of the source code, whereas inlining only affects the generated binary. - Jonathan M DavisOn Friday, August 23, 2013 19:21:33 Gary Willoughby wrote:Make the templated function a stub which redirects to a function which uses normal function arguments and rely on inlining?I don't think you can bloat a simple logger too much with templates. It's a pretty simple framework.If __FILE__ and __LINE__ are template arguments to a logging function rather than function arguments (and you can't make __FILE__ and __LINE__ default function arguments if the function is variadic as it would have to be to support format strings), then you get a new template instantation every single time that you call the function, unless you call it more than once on the same line (which you're unlikely to ever do). I want to think that there's a way to handle this if you get clever, but I can't think of a clever way to get around the problem at the moment. - Jonathan M Davis
Aug 23 2013
Am Fri, 23 Aug 2013 16:08:40 -0400 schrieb "Jonathan M Davis" <jmdavisProg gmx.com>:On Friday, August 23, 2013 21:47:44 Johannes Pfau wrote:I think you misunderstood. If you write code like this: void log(string file = __FILE__)() //A template { logImpl(file); } void logImpl(string file){} //Not a template The compiler can always inline the log template. So there's no template bloat as there will be effectively no instances of log. Instead it will be inlined and logImpl will be called directly just as if you manually called logImpl(__FILE__).Am Fri, 23 Aug 2013 15:16:05 -0400 schrieb "Jonathan M Davis" <jmdavisProg gmx.com>:Inlining will have no effect on __FILE__ and __LINE__, and it would be a bug if it did, because they're supposed to give the file and line number of the source code, whereas inlining only affects the generated binary.On Friday, August 23, 2013 19:21:33 Gary Willoughby wrote:Make the templated function a stub which redirects to a function which uses normal function arguments and rely on inlining?I don't think you can bloat a simple logger too much with templates. It's a pretty simple framework.If __FILE__ and __LINE__ are template arguments to a logging function rather than function arguments (and you can't make __FILE__ and __LINE__ default function arguments if the function is variadic as it would have to be to support format strings), then you get a new template instantation every single time that you call the function, unless you call it more than once on the same line (which you're unlikely to ever do). I want to think that there's a way to handle this if you get clever, but I can't think of a clever way to get around the problem at the moment. - Jonathan M Davis
Aug 23 2013
On 08/23/2013 10:08 PM, Jonathan M Davis wrote:On Friday, August 23, 2013 21:47:44 Johannes Pfau wrote:I think I came up with something good looking. A regex explains it best. log // still returns the default logger (LOGGER\.)?log\((LOGLEVEL,)? (CONDITION,)? (MESSAGE)?\) // normal logging without template bloat (LOGGER\.)?logf\((LOGLEVEL,)? (CONDITION,)? (MESSAGE), (ARGS,)*\) // printf logging with templates bloat I push the changes and the new docu (which needs some more work). Good night everybody.Make the templated function a stub which redirects to a function which uses normal function arguments and rely on inlining?Inlining will have no effect on __FILE__ and __LINE__, and it would be a bug if it did, because they're supposed to give the file and line number of the source code, whereas inlining only affects the generated binary. - Jonathan M Davis
Aug 23 2013
On Fri, Aug 23, 2013 at 03:16:05PM -0400, Jonathan M Davis wrote:On Friday, August 23, 2013 19:21:33 Gary Willoughby wrote:[...] Hmm. What about: void funcImpl(A...)(string file, int line, A args) { ... } template func(string file=__FILE__, int line=__LINE__, A...) { func(A args) { funcImpl(file, line, args); } } It still has template bloat in that func will be instantiated for every call though, but at least the function body isn't duplicated that many times. T -- A program should be written to model the concepts of the task it performs rather than the physical world or a process because this maximizes the potential for it to be applied to tasks that are conceptually similar and, more important, to tasks that have not yet been conceived. -- Michael B. AllenI don't think you can bloat a simple logger too much with templates. It's a pretty simple framework.If __FILE__ and __LINE__ are template arguments to a logging function rather than function arguments (and you can't make __FILE__ and __LINE__ default function arguments if the function is variadic as it would have to be to support format strings), then you get a new template instantation every single time that you call the function, unless you call it more than once on the same line (which you're unlikely to ever do). I want to think that there's a way to handle this if you get clever, but I can't think of a clever way to get around the problem at the moment.
Aug 23 2013
On 2013-08-23 18:48, Robert Schadek wrote:I do as well, but this will lead to template bloat, as many people will tell you, and log("device id: %s".format(device.id)); is not so bad.Won't it be just as much template bloat using "format"? -- /Jacob Carlborg
Aug 23 2013
On 08/23/2013 10:34 PM, Jacob Carlborg wrote:On 2013-08-23 18:48, Robert Schadek wrote:well yes, but log(A...)(A a) { format("...", a); } is worse ;-)I do as well, but this will lead to template bloat, as many people will tell you, and log("device id: %s".format(device.id)); is not so bad.Won't it be just as much template bloat using "format"?
Aug 23 2013
I would to drop some requirements I've seen in the Java world. * As klamonte mention in the pull request on GitHub: Appenders are a must in a enterprise enviorment. * Same with filters. In SLF4J normally each class has it's own logger which can be filtered or appended to individual files. * Runtime configuration. Crucial when collection data about bugs in running systems. * Performance... The possibility to write asynchronous loggers. * Sometimes it's expensive to construct the log output. In Java for example Logback calls toString on objects after it has concluded that the data is needed. So a possibility to pass an function for constructing the log output only when the logger is sure that it's going to be logged. My 2 SEK. ;-)
Sep 07 2013