Re: Let's bikeshed std.experimental.testing assertions/checks/whatchamacallits
1. 'assert' is the wrong thing I do not need a stack trace for a failed expectation in a unit test. But, usually, I need a stack trace for a contract violation from deep down in the unit under test: https://github.com/linkrope/dunit#failures-vs-errors Consequently, the failed expectation should throw some "failed expectation" 'Exception' instead of an 'AssertError'. So, std.exception.assertThrown cannot be used for expectations. 2. something like an 'assert' with better diagnostics could be nice Catch for C++ introduced 'REQUIRE' with helpful failure messages: Example.cpp:9: FAILED: REQUIRE( Factorial(0) == 1 ) with expansion: 0 == 1 https://github.com/philsquared/Catch 3. 'should' seems to be obsolete Now, 'expect' should be used for expectations: http://rspec.info/blog/2012/06/rspecs-new-expectation-syntax/
Re: D Meetup in Berlin
I would like to join. The problem is, that I'm working in Munich (at Funkwerk). But almost every Friday I will be in Berlin. So, it would be great if such a Meetup could be on a Friday.
Re: Voting: std.logger
On Thursday, 31 July 2014 at 07:13:37 UTC, Kagamin wrote: On Wednesday, 30 July 2014 at 20:41:15 UTC, Andrei Alexandrescu wrote: Yah but then we have stuttering such as log.log("ehm") which is oddly the same as log("ehm"). log.write log.writef And with alias writef opCall; (from the previous std.log proposal) it could also be log("ehm");
Re: Voting: std.logger
On Wednesday, 30 July 2014 at 18:08:12 UTC, Andrei Alexandrescu wrote: On 7/30/14, 10:50 AM, linkrope wrote: On Wednesday, 30 July 2014 at 17:01:39 UTC, Andrei Alexandrescu wrote: On 7/30/14, 8:16 AM, Kagamin wrote: On Wednesday, 30 July 2014 at 14:59:38 UTC, Andrei Alexandrescu wrote: Such logic doesn't apply to vocabularies. According to my vocabulary, a logger is something that logs. Didn't hear about irater, and messer sounds like a German word. Yah but the log object, i.e. the thing you log things in (the paper log on a ship etc) is "a log", not "a logger". A "logger" would be the person writing into the log. So the appropriate name for the default log object is "defaultLog" not "defaultLogger", or "stdlog" not "stdlogger". The better choice is also shorter. Andrei Even shorter would be "log". That would be better than enabling log.info(...); via the already proposed import log = std.logger; The only obstacle is the current "log" function. But do we really need the free log functions? For UFCS? Otherwise alias info = log.info; would do the trick. But here we're discussing the name of the default log object... -- Andrei Yes: most of the time I should be happy with the default log object. Call it "log" and the uses look great: log.error("something went wrong");
Re: Voting: std.logger
On Wednesday, 30 July 2014 at 17:01:39 UTC, Andrei Alexandrescu wrote: On 7/30/14, 8:16 AM, Kagamin wrote: On Wednesday, 30 July 2014 at 14:59:38 UTC, Andrei Alexandrescu wrote: Such logic doesn't apply to vocabularies. According to my vocabulary, a logger is something that logs. Didn't hear about irater, and messer sounds like a German word. Yah but the log object, i.e. the thing you log things in (the paper log on a ship etc) is "a log", not "a logger". A "logger" would be the person writing into the log. So the appropriate name for the default log object is "defaultLog" not "defaultLogger", or "stdlog" not "stdlogger". The better choice is also shorter. Andrei Even shorter would be "log". That would be better than enabling log.info(...); via the already proposed import log = std.logger; The only obstacle is the current "log" function. But do we really need the free log functions? For UFCS? Otherwise alias info = log.info; would do the trick.
Re: Voting: std.logger
On Wednesday, 30 July 2014 at 14:25:49 UTC, David Nadlinger wrote: On a note less related to bikes, could anybody explain to me why a name is something natural to a logger? In other words, why does it make sense to complicate the entire design with this instead of just using either a set (in place of a map) in MultiLogger or at least keeping the whole name concept local to it? Cheers, David In addition: The setter property for the name of the logger together with the sorting of loggers by name and 'assumeSorted' will cause trouble.
Re: Voting: std.logger
On Tuesday, 29 July 2014 at 17:31:27 UTC, Robert burner Schadek wrote: On Tuesday, 29 July 2014 at 17:20:58 UTC, Andrei Alexandrescu wrote: I should have the overload approach done by tonight Have a look at https://github.com/linkrope/log/blob/master/src/log.d#L55-66 for the overloading. It's much cleaner than the 'static if' sequences.
Re: Review: std.logger
On Tuesday, 22 July 2014 at 23:43:59 UTC, Robert burner Schadek wrote: On Tuesday, 22 July 2014 at 21:52:09 UTC, linkrope wrote: Controversial conditional logging The only advantage of tracec(condition, "passed"); over if (condition) trace("passed"); would be, that a costly evaluation of the condition is omitted when there is no trace logger. That's why the std.log proposal had 'when(lazy bool now)'. First, I was puzzled about your argument that LOG_FIRST_N or LOG_EVERY_N would be no problem with the '...c' functions. But a look at the implementation confirmed that the std.logger has no lazy evaluation of the condition; discarding the only advantage. passing a bool as a delegate that is the first thing that gets evaluated does not sound right. Indeed: that's why the lazy condition should be evaluated last! Your "will log" condition is very simple and efficient: only >= and != But you cannot know, how long the evaluation of the user-provided condition will take. BTW: with 'globalLogLevel', 'defaultLogger.logLevel'and 'LogLevel.off' the usual 'willLog' predicate will come in handy to avoid code duplication. While the lazy evaluation of the condition would be the only advantage over if (condtion) log(...); I haven't encountered a single opportunity for conditional logging in the code of our company. 'if'/'log' is always followed by 'return', 'break', 'continue', ... if (condition) { log("will do something else because condition passed"); return; }
Re: Review: std.logger
Sorry, but at the first contact with the implementation (the one with 'genDocComment' and 'buildLogFunction' from months ago) I was scared away. (It's better now.) I feared that if I criticize the 'mixin' sequences you would ask something like "suggestions?" ;-) So, I made this experiment to provide an answer. Now, I can suggest: try something like this: alias trace = log!(LogLevel.trace); alias info = log!(LogLevel.info); alias warn = log!(LogLevel.warn); alias error = log!(LogLevel.error); alias fatal = log!(LogLevel.fatal); (see https://github.com/linkrope/log/blob/master/src/log.d) Controversial conditional logging The only advantage of tracec(condition, "passed"); over if (condition) trace("passed"); would be, that a costly evaluation of the condition is omitted when there is no trace logger. That's why the std.log proposal had 'when(lazy bool now)'. First, I was puzzled about your argument that LOG_FIRST_N or LOG_EVERY_N would be no problem with the '...c' functions. But a look at the implementation confirmed that the std.logger has no lazy evaluation of the condition; discarding the only advantage. Sets of log levels -- No! Of course, I can log (trace | info) to stdout, warn.orHigher to stderr, and for instance info.orHigher to some file. Simplicity "The simplest way to achieve simplicity is through thoughtful reduction." We started with tango.util.log (best described as log4j for D). We are happier now with a lot less functionality, but on the other hand with the simplest API that works. On Monday, 21 July 2014 at 22:53:27 UTC, Robert burner Schadek wrote: On Sunday, 20 July 2014 at 16:15:53 UTC, linkrope wrote: Pros The lighning talk about the std.logger proposal at DConf 2014 had a positive impact. We were able to change the "Current D Use" entry of our company from "Uses D2 / Phobos, Tango (log, xml)" to "Uses D2 / Phobos, Tango (xml)". (We got rid of tango.util.log; we still rely on the fast tango.text.xml.) I didn't expect to hear from you about this, after you did not reply to my email about this topic. If xml is problem for you, where is the PR? Cons 1. I am not happy with the (reverse) hungarian-style naming At least in the code of our company, logging a formatted string is the basic use case. The function for the basic use case should not require a suffix letter. The consistency argument, that 'infof' is like 'writef', does not fully apply: neither 'infoln' nor 'infofln' make sense. (In my opinion, "half consistent" is inconsistent.) so we have gone full circle now Currently, suffix 'c' is used for conditional logging. But, how will future extensions like glog's LOG_EVERY_N or LOG_FIRST_N be named? That's an easy one. ``` auto a = LOG_FIRST_N(1337); logc(a, "Hello world"); auto b = WHAT_EVERY_THE(); logc(b, "Hello world again"); ``` With suffix 'e'? Suffix 'f' is already assigned! what is 'e'? The suffix letter sequence seems to be the road to confusion. I would prefer the explicit naming of the previous std.log proposal: log.when(condition)(...) However, there is only a small advantage over if (condition) log(...) ... 2. No support for 24/7 (server) applications In my opinion, I really need logging for applications that possibly run forever. With the FileLogger, the file will grow forever. That's why most other frameworks provide something like a RollingFileLogger or some "logrotate-aware" FileLogger. By the way: Instead of what I really need, I get a NullLogger. I have no clue, why I never ever missed such an oddity. That was a user request, through github. Where I asked you to submit PRs and issues. Have you tried subclassing Logger? I asked for PRs in the email I wrote to you at least twice. 3. Implementation is hidden behind 'mixin' expressions When I tried to look at the implementation, I found long sequences of lines like this: mixin(buildLogFunction(true, false, false, LogLevel.info)); Nowadays, this changed into: mixin(freeLog.format( "info", "info", "info", "info", "info", "info", "info", "info", "info", "info", "info", "info", "info", "info", "info", "info")); This is much better, but I still think, it's a complicated solution for a simple problem. And it would be a shame for D, if there is no simple solution. Yes please, suggestions? Small stuff --- 4. FileLogger needs flush It's annoy
Re: Review: std.logger
On Tuesday, 22 July 2014 at 09:51:24 UTC, ponce wrote: On Tuesday, 22 July 2014 at 08:44:06 UTC, linkrope wrote: On Tuesday, 22 July 2014 at 07:27:38 UTC, ponce wrote: On Sunday, 20 July 2014 at 16:15:53 UTC, linkrope wrote: By the way: Instead of what I really need, I get a NullLogger. I have no clue, why I never ever missed such an oddity. I asked for it. And I use it, because I write libraries that log warnings but don't forcefully require the users to provide a Logger if they don't want to. And that way, I can still write "logger.warningf" without "if" everywhere. But then it's better to provide no logger (or at least no logger for level warning) than an artificial NullLogger. My need is not "artificial", at least in my view. Your opinion is different from mine. That's fine. That's why we need someone to try to reconcile the many, many opinions about this. Not the need is artificial. For example, I have the need to measure the performance of an application with and without logging. I think, the solution is artificial. The obvious solution would be to register no logger at all.
Re: Review: std.logger
On Tuesday, 22 July 2014 at 07:27:38 UTC, ponce wrote: On Sunday, 20 July 2014 at 16:15:53 UTC, linkrope wrote: By the way: Instead of what I really need, I get a NullLogger. I have no clue, why I never ever missed such an oddity. I asked for it. And I use it, because I write libraries that log warnings but don't forcefully require the users to provide a Logger if they don't want to. And that way, I can still write "logger.warningf" without "if" everywhere. But then it's better to provide no logger (or at least no logger for level warning) than an artificial NullLogger.
Re: Review: std.logger
Pros The lighning talk about the std.logger proposal at DConf 2014 had a positive impact. We were able to change the "Current D Use" entry of our company from "Uses D2 / Phobos, Tango (log, xml)" to "Uses D2 / Phobos, Tango (xml)". (We got rid of tango.util.log; we still rely on the fast tango.text.xml.) Cons 1. I am not happy with the (reverse) hungarian-style naming At least in the code of our company, logging a formatted string is the basic use case. The function for the basic use case should not require a suffix letter. The consistency argument, that 'infof' is like 'writef', does not fully apply: neither 'infoln' nor 'infofln' make sense. (In my opinion, "half consistent" is inconsistent.) Currently, suffix 'c' is used for conditional logging. But, how will future extensions like glog's LOG_EVERY_N or LOG_FIRST_N be named? With suffix 'e'? Suffix 'f' is already assigned! The suffix letter sequence seems to be the road to confusion. I would prefer the explicit naming of the previous std.log proposal: log.when(condition)(...) However, there is only a small advantage over if (condition) log(...) 2. No support for 24/7 (server) applications In my opinion, I really need logging for applications that possibly run forever. With the FileLogger, the file will grow forever. That's why most other frameworks provide something like a RollingFileLogger or some "logrotate-aware" FileLogger. By the way: Instead of what I really need, I get a NullLogger. I have no clue, why I never ever missed such an oddity. 3. Implementation is hidden behind 'mixin' expressions When I tried to look at the implementation, I found long sequences of lines like this: mixin(buildLogFunction(true, false, false, LogLevel.info)); Nowadays, this changed into: mixin(freeLog.format( "info", "info", "info", "info", "info", "info", "info", "info", "info", "info", "info", "info", "info", "info", "info", "info")); This is much better, but I still think, it's a complicated solution for a simple problem. And it would be a shame for D, if there is no simple solution. Small stuff --- 4. FileLogger needs flush It's annoying when the events that caused a crash have been logged, but they never have been written to the file. 5. Suspect use of '__gshared' The FileLogger has a field private __gshared File file_; In this case, "__gshared is equivalent to static". This means that all FileLogger instances share the same file! 6. Bad naming of "StdIOLogger" Like 'std.stdio.StdioException', the 'io' should be lower case. If the 'StdIOLogger' logs to 'stdout', 'StdoutLogger' would be preferable. 7. No need for StdIOLogger 'stdout' (and 'stderr') are Files, so a FileLogger should be able to handle them. A second constructor should do the trick. 8. Log levels Many frameworks mix the types "log level" and "set of log levels" (for filtering). While 'trace', ..., 'fatal' are log levels, 'all' and 'off' (better: 'none'?) are sets of log levels. (I have no idea about the type of 'unspecific'.) A clean separation would avoid confusion: why is there 'info(...)' but not 'all(...)'? Also, it would be easier to log for example 'trace' and 'info' to 'stdout'. 9. Bad naming of "std.logger" The focus of this proposal is on the log/logging API; the loggers are only examples. The recommended use should be import log = std.logger; Then, the name "std.log" (of the previous proposal) would be more appropriate. Counter Proposal As a consequence of these issues, I once decided to spend a weekend to prepare a counter proposal: http://code.dlang.org/packages/log The design goal was simplicity. So: - conditional logging is not supported - no suffix letter sequences - there is no NullLogger - there is no MultiLogger (this functionality is implicit) - there is no need to provide a name for a logger I prefer 'alias' over 'mixin': 'info' is just an alias for 'log(arg)' as well as for 'log(fmt, args)' at log level 'info'. Sets of log levels are implemented as (bit) sets of log levels. A helper function lets you select the traditional >= filtering: LogLevel.info.orHigher For convenience, 'stdoutLogger' and 'stderrLogger' are factory functions that create 'FileLogger' instances. Of course, a RollingFileLogger as well a a "RotatingFileLogger" (that reopens the log file on SIGHUP) are provided. By now, this simple solution is in use in tens of thousands lines of commercial code. (Where it outperforms the previously used tango.util.log implementation.)
Re: Review: std.logger
What does 'errorlcf' mean? You specify log level 'error' and then you specify another log level ('l): which log level wins? The order of these modifier letters has to be 'lcf', not 'cfl', ...? On Tuesday, 15 July 2014 at 08:01:12 UTC, Robert burner Schadek wrote: I wouldn't call them cryptic, they are in fact very easy. l = LogLevel c = conditional f = printf what is so difficult about them. Sure errorIf looks easier, but what about errorLogLevelIfPrintfFormat in comparison to errorlcf