digitalmars.D - Voting: std.logger
- Dicebot (30/30) Jul 28 2014 (sorry for being a bit late, was distracted)
- Dicebot (12/12) Jul 28 2014 Small foreword specifically about std.logger :
- Jakob Ovrum (23/28) Jul 28 2014 If modules in std.experimental are completely free to make
- Rikki Cattermole (12/40) Jul 28 2014 Yes,
- Andrei Alexandrescu (69/88) Jul 28 2014 My vote is a qualified "yes" contingent upon fixes that I'll give detail...
- Dicebot (11/16) Jul 28 2014 Clarification, just to be sure you got it right - right now we
- Andrei Alexandrescu (5/18) Jul 29 2014 I explained in the non-negotiable points. The point of keeping a module
- David Nadlinger (8/10) Jul 29 2014 I agree. For this reason, I also vote for "no" (1 as well as 2),
- Robert burner Schadek (32/106) Jul 29 2014 I'm not sure how you except log(LogLevel.xxxx, "Hello world") to
- H. S. Teoh via Digitalmars-d (7/17) Jul 29 2014 [...]
- Andrei Alexandrescu (4/18) Jul 29 2014 I thought of the same but then rejected it - stdlog looks like offering
- H. S. Teoh via Digitalmars-d (5/26) Jul 29 2014 I don't like 'theLog'. What about 'defaultLog'?
- uri (5/38) Jul 29 2014 +1 for !theLog. I actually like "dlog" because I hate typing but
- Marco Leise (3/25) Aug 26 2014 appLog/applog
- Andrei Alexandrescu (16/51) Jul 29 2014 In all likelihood I misunderstood you! Whenever a LogLevel is passed
- "Marc =?UTF-8?B?U2Now7x0eiI=?= <schuetzm gmx.net> (8/19) Jul 30 2014 I don't see anything wrong with "logger". A "driver" is something
- Daniel Murphy (3/9) Jul 30 2014 I agree with this too. All of it.
- David Nadlinger (11/21) Jul 30 2014 +1. theLog seems unintuitive to me. It's not like Logger is some
- linkrope (4/12) Jul 30 2014 In addition:
- David Nadlinger (14/20) Jul 30 2014 Wow, upon further code review I discovered that Logger actually
- Andrei Alexandrescu (5/23) Jul 30 2014 Such logic doesn't apply to vocabularies. Is an "irater" someone who
- Kagamin (4/5) Jul 30 2014 According to my vocabulary, a logger is something that logs.
- Andrei Alexandrescu (8/12) Jul 30 2014 Yah but the log object, i.e. the thing you log things in (the paper log
- Daniel Murphy (4/10) Jul 30 2014 But the default log object is the tool you use to write things into the ...
- Andrei Alexandrescu (7/19) Jul 30 2014 No, the way I see it is myLog.write("stuff"), i.e. it's me, the caller,
- Daniel Murphy (2/7) Jul 30 2014 It's subjective either way. Isn't language fun!
- David Nadlinger (10/13) Jul 30 2014 I'm not going to join a discussion about the finer details of
- linkrope (12/27) Jul 30 2014 Even shorter would be "log".
- Andrei Alexandrescu (2/30) Jul 30 2014 But here we're discussing the name of the default log object... -- Andre...
- linkrope (6/52) Jul 30 2014 Yes: most of the time I should be happy with the default log
- Andrei Alexandrescu (3/6) Jul 30 2014 Yah but then we have stuttering such as log.log("ehm") which is oddly
- Kagamin (4/6) Jul 31 2014 log.write
- linkrope (5/11) Jul 31 2014 And with
- eles (8/20) Jul 31 2014 log.note()
- Andrei Alexandrescu (3/8) Jul 31 2014 Then you have the globals write and writef which will compete with those...
- Kagamin (3/5) Aug 01 2014 Aren't they from different overload sets?
- Andrei Alexandrescu (2/6) Aug 01 2014 Doesn't seem to me. They all accept e.g. one string. -- Andrei
- Dicebot (4/13) Aug 01 2014 So what is the problem? We have module system to resolve that, do
- Andrei Alexandrescu (4/14) Aug 01 2014 Yah but there's this inconvenience when people import two stdlib modules...
- Martin Nowak (7/17) Aug 01 2014 Exactly, that's the problem. They collide, so when import both the
- Martin Nowak (3/9) Aug 01 2014 We already have a similar issue with std.stdio.write and std.file.write
- Dicebot (12/20) Aug 01 2014 Solution is easy - don't do `import std.log` an don't recommend
- Daniel Murphy (3/6) Aug 01 2014 It's easy, but it's not the easiest. There is a lot of value in having ...
- Dicebot (3/10) Aug 01 2014 I am afraid we don't have the right way in D then. Caring about
- Daniel Murphy (7/9) Aug 01 2014 But with overloading!
- Dicebot (10/22) Aug 01 2014 If you find this important, you can always require renamed /
- Andrei Alexandrescu (8/27) Aug 01 2014 To an extent I agree, but I have to side with the view that common
- Timon Gehr (3/4) Aug 01 2014 The newly introduced _private_ aliases would have possibly led to more
- Daniel Murphy (6/8) Aug 02 2014 I don't like manual name mangling, but I like being able to look at a li...
- Kagamin (2/5) Aug 01 2014 Can you tell, what `log(1)` does?
- Timon Gehr (2/6) Aug 01 2014 It returns 0. No, wait...
- Jeremy Powers via Digitalmars-d (9/10) Aug 01 2014 Is there a irrefutable requirement to have a log function without explic...
- Kagamin (6/12) Aug 03 2014 As I understand, it's a defensive feature. There are things one
- Jeremy Powers via Digitalmars-d (5/13) Aug 04 2014 Believe that's what the 'off' level is for, though it is confusingly nam...
- Jeremy Powers via Digitalmars-d (8/18) Aug 04 2014 Looking at the current version of the logger code, there is nothing that
- Kagamin (4/4) Aug 05 2014 'always' or 'unfiltered'
- Kagamin (7/10) Jul 31 2014 Logging to a paper log is done directly without a logger. A
- "Marc =?UTF-8?B?U2Now7x0eiI=?= <schuetzm gmx.net> (12/38) Jul 30 2014 Yes. It's called "derivation" in linguistics. It works in this
- Martin Nowak (4/9) Jul 31 2014 Here is a proof of concept to achieve this.
- Martin Nowak (24/35) Aug 01 2014 Just checked tested this.
- Vladimir Panteleev (8/15) Aug 31 2014 FWIW:
- =?UTF-8?B?TWFydGluIERyYcWhYXI=?= via Digitalmars-d (13/32) Jul 28 2014 Yes.
- John Colvin (6/10) Jul 29 2014 No. Full advantage should be taken of the std.experimental time.
- Casey (33/38) Jul 29 2014 I can't say Yes until I've actually used it.
- Robert burner Schadek (2/2) Jul 29 2014 maybe we should have made a vote for logc vs. log(bool) first
- Dicebot (4/6) Jul 29 2014 This shouldn't affect inclusion to std.experimental and can be
- Andrei Alexandrescu (7/13) Jul 29 2014 NO.
- Dicebot (4/11) Jul 29 2014 Spawned separate discussion thread :
- Andrei Alexandrescu (4/6) Jul 29 2014 My understanding is the entire prefix-letter approach was based on an
- Andrei Alexandrescu (2/9) Jul 29 2014 s/prefix/suffix/
- Robert burner Schadek (3/3) Jul 29 2014 On Tuesday, 29 July 2014 at 17:20:58 UTC, Andrei Alexandrescu
- linkrope (6/9) Jul 29 2014 Have a look at
- Robert burner Schadek (2/6) Jul 29 2014 of course, because you are doing much less
- Andrei Alexandrescu (3/10) Jul 29 2014 The idea would be to push the static ifs from inside the function into
- destroyer (4/12) Jul 29 2014 Andrei is Romanian; not Hungarian.
- Francesco Cattoglio (9/15) Jul 29 2014 Not yet.
- Byron Heads (19/24) Jul 29 2014 No
- Casey (3/6) Jul 29 2014 I should have said this as well. Regardless, I second this
- Jesse Phillips (1/1) Jul 29 2014 Yes for experimental.
- ponce (4/25) Jul 29 2014 Yes. A lot of reusable components need warnings (hence: logging).
- Sean Kelly (1/1) Jul 29 2014 Yes, assuming Andrei's non-negotiable issues are addressed first.
- MrSmith (1/1) Jul 30 2014 Yes for inclusion into std.experimental
- Martin Nowak (26/46) Jul 31 2014 No, as much as I'd like to have logging facilities in phobos, there are
- Andrei Alexandrescu (2/5) Jul 31 2014 Wait, doesn't code work with the version chosen by the user? -- Andrei
- Martin Nowak (14/19) Aug 01 2014 Well phobos as a library is precompiled, so the versions used to compile...
- Andrei Alexandrescu (4/25) Aug 01 2014 Oh I hadn't realized that. Thanks! That strengthens my opinion that more...
- Andrei Alexandrescu (6/8) Aug 01 2014 To clarify: I'm very strongly opposed to a design that requires
- Johannes Pfau (5/17) Aug 01 2014 It's kinda awkward how complicated the D solutions are compared to
- Kagamin (3/13) Aug 01 2014 Must be able, but should it be the only possible way?
- Andrei Alexandrescu (3/13) Aug 01 2014 Other ways would be also nice, but the primary use case is the user
- Robert burner Schadek (10/23) Aug 08 2014 could you elaborate please? Currently I use the version
- Martin Nowak (10/18) Oct 24 2014 For example we don't reinstatiate templates if they are
- Dicebot (2/2) Aug 10 2014 Voting ends tomorrow, summary post may get delayed for a few days
- Robert burner Schadek (19/19) Aug 17 2014 thank you Dicebot for the work.
- Dicebot (5/25) Aug 18 2014 Eventually I am going to go through the list of requirements from
- Andrei Alexandrescu (5/21) Aug 18 2014 This is very promising! Has the versioning issue been solved? I.e. we
- Robert burner Schadek (8/11) Aug 19 2014 There is now a template function with version statements inside
- Andrei Alexandrescu (6/16) Aug 19 2014 This is great, thanks. Not only this will be a good thing for
- Robert burner Schadek (6/7) Aug 19 2014 I guess I have to freshen up my dmd compilation flow knowledge.
- "Ola Fosheim =?UTF-8?B?R3LDuHN0YWQi?= (7/7) Aug 20 2014 - Regarding i18n: I think you should avoid using natural language
- Robert burner Schadek (12/19) Aug 26 2014 example, please?
- Andrei Alexandrescu (3/4) Aug 26 2014 One more round of reviews and let's merge to experimental if all good.
- Dicebot (5/10) Aug 26 2014 I will compare changelist against list of requirements from
- Marco Leise (25/37) Aug 26 2014 Someone else mentioned it before: Logging in destructors would
- Robert burner Schadek (16/21) Aug 26 2014 nothrow I get, but nothrow in dtors is a much wider topic (please
- Marco Leise (17/33) Aug 26 2014 You are right.
- Dicebot (10/22) Aug 26 2014 I don't think it will help either. The very moment exception is
- Marco Leise (11/36) Aug 26 2014 Exactly, I just needed someone else to speak it out. :)
- Dicebot (10/20) Aug 28 2014 I really believe that necessity to log something in dtor is
- eles (3/10) Aug 27 2014 It would be a pity to have forbidden spaces for logging. I very
- Robert burner Schadek (4/7) Aug 26 2014 sounds good!
- Dicebot (140/148) Aug 29 2014 Ok, going through the list of "No" voters.
- Dicebot (27/27) Aug 29 2014 ==============================
- Dicebot (11/11) Aug 29 2014 I have likely missed several points but overall it seem pretty
- Andrei Alexandrescu (3/6) Aug 30 2014 How do the remaining issues break down into QoI that can be deferred to
- Dicebot (3/11) Aug 30 2014 What is QoI? I am not familiar with this abbreviation
- H. S. Teoh via Digitalmars-d (5/15) Aug 30 2014 Quality of Implementation.
- Dicebot (4/10) Aug 30 2014 And how can one break issues into quality of implementation? :O I
- H. S. Teoh via Digitalmars-d (6/17) Aug 30 2014 I'm guessing he means, break them down into must-solve-before-merge
- Andrei Alexandrescu (2/16) Aug 30 2014 Correct. (I'm on vacation with scarce online access.) -- Andrei
- Dicebot (5/6) Aug 30 2014 With API stability in mind defining official stance on
- "Ola Fosheim =?UTF-8?B?R3LDuHN0YWQi?= (8/8) Aug 30 2014 I've got some questions:
- Marco Leise (19/27) Aug 30 2014 Am Sun, 31 Aug 2014 01:09:32 +0000
- "Ola Fosheim =?UTF-8?B?R3LDuHN0YWQi?= (10/18) Aug 31 2014 1. ~90% of all functions are weakly pure, if you cannot log
- Marco Leise (17/38) Aug 31 2014 Am Sun, 31 Aug 2014 08:52:58 +0000
- eles (13/24) Aug 31 2014 Why would that be the sole outcome? There are several strategies
- "Ola Fosheim =?UTF-8?B?R3LDuHN0YWQi?= (15/23) Aug 31 2014 Then maybe the language lacks features that allow you to escape
- Kevin Lamonte (6/10) Aug 31 2014 Does this logger already exist, could I take a look at it?
- "Ola Fosheim =?UTF-8?B?R3LDuHN0YWQi?= (9/13) Sep 01 2014 Not in D AFAIK, circular in-memory logging is a common technique
- Kevin Lamonte (25/32) Sep 01 2014 I'm used to a centralized system taking logs on a continuous
- "Ola Fosheim =?UTF-8?B?R3LDuHN0YWQi?= (29/51) Sep 02 2014 Yes, I think we are discussing many different things at the same
- Kevin Lamonte (56/69) Sep 03 2014 I've written my own ideas about logging vs tracing over at
- "Ola Fosheim =?UTF-8?B?R3LDuHN0YWQi?= (38/47) Sep 03 2014 Nice writeup! It is kind of interesting that there are so many
- Kevin Lamonte (10/19) Sep 03 2014 I've got a feature request in for just that:
- "Ola Fosheim =?UTF-8?B?R3LDuHN0YWQi?= (13/15) Sep 03 2014 Interesting! I am not 100% convinced that scope(failure/success)
- "Ola Fosheim =?UTF-8?B?R3LDuHN0YWQi?= (7/9) Sep 03 2014 I meant: you might need to "increment a stack specific counter",
- Dicebot (5/15) Sep 05 2014 This can already be implemented in a library if "mixin of an
- Kevin Lamonte (11/18) Sep 06 2014 Since we are talking about performance, I did some tests and
- "Ola Fosheim =?UTF-8?B?R3LDuHN0YWQi?= (13/17) Sep 06 2014 I think maybe we should start with creating a high performance
- Robert burner Schadek (5/17) Sep 09 2014 that is with all likelihood a syscall, so there goes your
- Dicebot (13/21) Sep 01 2014 Weakly pure function can take logger as an argument (so I doubt
- "Ola Fosheim =?UTF-8?B?R3LDuHN0YWQi?= (12/19) Sep 01 2014 […]
- Dicebot (9/18) Sep 01 2014 You are totally misunderstanding goals of std.logger - people as
- Dicebot (2/4) Sep 01 2014 *are expected
- "Ola Fosheim =?UTF-8?B?R3LDuHN0YWQi?= (16/23) Sep 01 2014 Oh, I understand the intentions perfectly well, but the default
- eles (8/17) Sep 01 2014 +1
- Dicebot (11/21) Sep 02 2014 I disagree and it was declared among goals of this module from
- "Ola Fosheim =?UTF-8?B?R3LDuHN0YWQi?= (16/22) Sep 02 2014 Configuration of logging is part of the API.
- Dicebot (10/22) Sep 02 2014 Sorry but it doesn't work that way. If you are concerned about
- "Ola Fosheim =?UTF-8?B?R3LDuHN0YWQi?= (17/21) Sep 02 2014 Uhm, it isn't theoretical. A low performance string based
- Dicebot (12/33) Sep 02 2014 This is exactly what I call theoretical speculations. Please
- "Ola Fosheim =?UTF-8?B?R3LDuHN0YWQi?= (32/34) Sep 02 2014 I am not abstract. These are very concrete requirements:
- Dicebot (8/17) Sep 05 2014 Ok, this is much more specific. With a similar concerns in mind I
- Dicebot (4/11) Sep 05 2014 P.S. Reason why compile-time format checking can't be added to
- "Ola Fosheim =?UTF-8?B?R3LDuHN0YWQi?= (12/15) Sep 05 2014 Hm. My experience with Python for server use tells me that the
- Kevin Lamonte (44/47) Sep 02 2014 I propose the following API changes (+ changes on default
- Robert burner Schadek (7/56) Sep 08 2014 The only problem with that change is that it will always require
- Kevin Lamonte (3/3) Sep 03 2014 Another API change: LogEntry must have a Thread reference,
- Jakob Ovrum (3/14) Aug 30 2014 Implementation issues can be fixed later as long as the API
- Robert burner Schadek (6/18) Sep 09 2014 I made the stdlog creating thread-safe and on stack. I think that
- Dicebot (7/19) Sep 09 2014 This unfortunately makes it almost unusable in absence of
- Andrei Alexandrescu (7/17) Sep 10 2014 There may be a miscommunication here. In short:
- Robert burner Schadek (6/12) Sep 10 2014 But
- Dicebot (4/8) Sep 10 2014 And this is why I am asking for separate `logRaw` overload that
- Jacob Carlborg (6/9) Sep 10 2014 Could we modify the compiler to allow that? Just for the special
- Robert burner Schadek (4/12) Sep 10 2014 IMO that is overkill, adding another another method that only
- Dicebot (6/14) Sep 10 2014 This is much desired compiler enhancement in my opinion (this
- Robert burner Schadek (3/7) Sep 10 2014 killing this special overload, once the compiler does this,
- Daniel Murphy (2/5) Sep 10 2014 IIRC Andrei has a bugzilla open for this.
- Timon Gehr (6/11) Sep 10 2014 Why? I cannot remember a compiler version where the following did not wo...
- Robert burner Schadek (4/10) Sep 10 2014 For every instantiation of of fun there will be a new symbol even
- Daniel Murphy (3/8) Sep 10 2014 Not in that example there won't.
- Robert burner Schadek (4/10) Sep 10 2014 For every instantiation of of fun there will be a new symbol even
- Daniel Murphy (3/9) Sep 10 2014 Hmm, do it does. Maybe I was thinking of this:
- Dicebot (3/19) Sep 10 2014 This is new to me - I can definitely remember trying it and
- =?UTF-8?B?U8O2bmtlIEx1ZHdpZw==?= (9/21) Sep 10 2014 Except that it unfortunately doesn't do what is intended:
- Timon Gehr (6/31) Sep 10 2014 Oops! Touché! Thanks. While the code indeed works, there actually _is_
- Andrei Alexandrescu (2/4) Sep 10 2014 Please bugzillize. Thanks! -- Andrei
- Andrei Alexandrescu (10/27) Sep 10 2014 One possibility is to have the first function be a one-liner that
- Dicebot (10/19) Sep 10 2014 Those are already small functions AFAIK (I was speaking about
- Timon Gehr (4/22) Sep 10 2014 Another possibility would be to fix this bug, but the mechanism isn't
- Robert burner Schadek (6/6) Sep 16 2014 On Wednesday, 10 September 2014 at 16:54:14 UTC, Dicebot wrote:
- Marco Leise (233/250) Sep 18 2014 WAT?
- Robert burner Schadek (6/9) Sep 19 2014 before every voting there is a review and I guess you started
- Marco Leise (14/28) Sep 19 2014 :)
- Robert burner Schadek (2/10) Sep 19 2014
- Marco Leise (7/8) Sep 19 2014 Ok, I'm working on it. From the looks of it I will iterate a
- Dicebot (3/5) Sep 20 2014 No, I provide purely management service here, aggregating
- Andrei Alexandrescu (2/13) Sep 19 2014 Nice, thanks! -- Andrei
- Dicebot (5/11) Sep 19 2014 Once you feel that thread safety concerns are addressed please
- Robert burner Schadek (2/15) Sep 08 2014 Overly complicated IMO
- Marco Leise (17/36) Sep 08 2014 This may sound surprising, but I believe if we want to make
- Robert burner Schadek (5/18) Sep 08 2014 I think the template bloat argument is invalid as __LINE__ and
- Robert burner Schadek (8/13) Sep 08 2014 The biggest problem I have currently with this that you, or at
- Marco Leise (13/29) Sep 08 2014 You are right, this benefit of classes doesn't apply here.
- Robert burner Schadek (3/11) Sep 08 2014 That should be a no-brainer just have a look at FileLogger and
- Kevin Lamonte (35/53) Aug 30 2014 I'm not a "voter" as far as I know, but I suggest that Logger is
- Jakob Ovrum (13/25) Aug 30 2014 Yes - split the `stdlog` property into a getter and a setter.
- Robert burner Schadek (9/61) Sep 08 2014 Every Logger has to have a LogLevel, interfaces won't work there
- Marco Leise (9/27) Sep 08 2014 =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
- Dicebot (6/16) Sep 08 2014 It should be possible to provide custom implementation that
- Robert burner Schadek (5/12) Sep 09 2014 catching an Exception from formattedWrite just to throw an Error
- Marco Leise (34/34) Sep 20 2014 Seeing how MultiLogger passes on the payload to its child
- Dicebot (7/11) Sep 20 2014 See also
- Marco Leise (4/4) Sep 20 2014 Ok, then here are my thread-safety changes for std.logger:
- Marco Leise (29/29) Sep 21 2014 Moved to: https://github.com/burner/phobos/pull/2
(sorry for being a bit late, was distracted) std.logger proposal by Robert Schadek enters voting period which will last two weeks starting from now. Discussion thread : http://forum.dlang.org/post/zhvmkbahrqtgkptdlcvh forum.dlang.org This voting will be somewhat different from previous ones because it will be done with std.experimental in mind. Because of that please reply with a bit more structured votes: 1) Yes / No for inclusion into std.experimental At this point please consider if module has functionality you want to see in standard library in general and if implementation is not fundamentally broken. This is a simple sanity check. 2) Yes / No for inclusion into Phobos in its current state This is where you should summarize your concerns raised during review if there are any and make decision if existing API / architecture are promising enough to be set in stone via Phobos inclusion. 3) If you have answered "No" for (2) : list of mandatory changes that are needed to make you vote "Yes" 4) Any additional comments for author. Please separate (3) from (4) in some obvious fashion to make it possible for author to prioritize of feedback. Please use linked thread for discussions and only post vote + summary here. Currently only answer for (1) affects the voting outcome. Other answers are necessary to eventually prepare std.logger for second voting during beta period of some future release (for actual inclusion into Phobos). If you have any comments / proposals about actual voting procedure or review process please create separate thread. Go ahead ;)
Jul 28 2014
Small foreword specifically about std.logger : It is quite clear that something like logging system is very opinionated thing with API/design preferences highly based on actual use cases. I don't think that we will ever be able to come up with decisions that will satisfy everyone - some compromises are necessary. Because of that, please think twice before declaring certain features crucial or API unacceptable - reserve such judgement only for something that is really a blocker for your work and will likely result in using completely different logging solution as opposed to building on top of std.logger And big thanks to Robert for being incredibly patient in pursuing inclusion of his proposal despite all the time it has taken!
Jul 28 2014
On Tuesday, 29 July 2014 at 05:11:33 UTC, Dicebot wrote:1) Yes / No for inclusion into std.experimentalIf modules in std.experimental are completely free to make breaking changes, then my vote is a clear yes. I'm uncertain if std.experimental can carry its own weight in the presence of dub, but I guess that's a discussion for another thread.2) Yes / No for inclusion into Phobos in its current stateNo. IMO, both API and implementation are insufficient. Additionally, the "current state" is extremely volatile with sweeping API changes being made in the last two weeks or so. However, review is on-going and at this rate, I'm hopeful it will be good enough by the next vote.3) If you have answered "No" for (2) : list of mandatory changes that are needed to make you vote "Yes"a) The *API* must support minimal dynamic memory allocation for the normal execution path. However, theoretical *implementation* changes that reduce memory allocation are not a deal-breaker. b) API must specify a strong stance on threading, whatever the form it takes. c) This one might seem unnecessarily strict, but I think the fact that Logger is a class and not an interface smells of poor design. I might still be convinced that having it as a class is justified, but my current stance is that it must be an interface.4) Any additional comments for author.The author is aware of my gripes from Github comments and posts in the review thread.
Jul 28 2014
On 29/07/2014 5:11 p.m., Dicebot wrote:(sorry for being a bit late, was distracted) std.logger proposal by Robert Schadek enters voting period which will last two weeks starting from now. Discussion thread : http://forum.dlang.org/post/zhvmkbahrqtgkptdlcvh forum.dlang.org This voting will be somewhat different from previous ones because it will be done with std.experimental in mind. Because of that please reply with a bit more structured votes: 1) Yes / No for inclusion into std.experimental At this point please consider if module has functionality you want to see in standard library in general and if implementation is not fundamentally broken. This is a simple sanity check.Yes, I have not tested it, just for reference sake. But the code design looks fine. Nicely documented with unittests.2) Yes / No for inclusion into Phobos in its current state This is where you should summarize your concerns raised during review if there are any and make decision if existing API / architecture are promising enough to be set in stone via Phobos inclusion.Yes But might be a good idea to add a Syslog and Windows event viewer logger(s) support.3) If you have answered "No" for (2) : list of mandatory changes that are needed to make you vote "Yes" 4) Any additional comments for author.Okay 1) update sidebar for phobos docs (atleast I couldn't see link to modules in there). 2) for std.logger.core defaultLogger please please please add that at the top of the page of documentation. Or else the very ability to change the default logger could be lost. It took me a while to find it.Please separate (3) from (4) in some obvious fashion to make it possible for author to prioritize of feedback. Please use linked thread for discussions and only post vote + summary here. Currently only answer for (1) affects the voting outcome. Other answers are necessary to eventually prepare std.logger for second voting during beta period of some future release (for actual inclusion into Phobos). If you have any comments / proposals about actual voting procedure or review process please create separate thread. Go ahead ;)
Jul 28 2014
On 7/28/14, 10:11 PM, Dicebot wrote:(sorry for being a bit late, was distracted) std.logger proposal by Robert Schadek enters voting period which will last two weeks starting from now. Discussion thread : http://forum.dlang.org/post/zhvmkbahrqtgkptdlcvh forum.dlang.org This voting will be somewhat different from previous ones because it will be done with std.experimental in mind. Because of that please reply with a bit more structured votes:My vote is a qualified "yes" contingent upon fixes that I'll give detail on below. In the current form my vote is "no" seeing as the module makes a number of unforced tactical errors. Overall I think the goods are there, and are easy to put in acceptable form.1) Yes / No for inclusion into std.experimental At this point please consider if module has functionality you want to see in standard library in general and if implementation is not fundamentally broken. This is a simple sanity check.No in current form. Yes assuming the fixes below are implemented.2) Yes / No for inclusion into Phobos in its current state This is where you should summarize your concerns raised during review if there are any and make decision if existing API / architecture are promising enough to be set in stone via Phobos inclusion.No. I also think any new module should sit in std.experimental for one release cycle.3) If you have answered "No" for (2) : list of mandatory changes that are needed to make you vote "Yes"Here's my list: 1. Minimal logging level must be selected statically in addition to the current dynamic selection. Static settings preclude dynamic settings. This is not negotiable. 2. All logging code must be rigorously eliminated if below the static logging level. More precisely, there must be a front-end optimization that eliminates all code dedicated to a "lazy" variable that's not used by a generic function. This would be a fantastic redeeming of the "lazy" keyword, which has been of marginal utility until now. The challenge here is cooperating with someone on the compiler team to make sure that front-end improvement gets implemented, and writing unit tests that make sure there's no regression later. This is not negotiable. 3. The suffix notations must be replaced with overloads. The only acceptable suffix is "f" for formatting. Everything else must be achieved via overloads with the help of template constraints. Robert's answer http://goo.gl/FehDVh suggests he didn't consider using template constraints. We can't let that slip become a feature of the library for millenia to come. The overloads must be: // just log stuff log(T...)(lazy T stuff) if (!is(T[0] : const LogLevel)); // log with format logf(S, T...)(lazy S fmt, lazy T stuff) if (isSomeString!Str); // log conditional with format logf(S, T...)(lazy bool cond, lazy S fmt, lazy T stuff) if (isSomeString!Str); These three overloads should be repeated for all logging functions (info, trace etc). The functions don't evaluate their arguments if the respective log level is disabled. The following functions will NOT be repeated for all logging functions: // just log stuff at some level log(T...)(LogLevel lvl, lazy T stuff) if (!is(T[0] : const LogLevel)); // log with format logf(S, T...)(LogLevel lvl, lazy S fmt, lazy T stuff) if (isSomeString!Str); // log conditional with format logf(S, T...)(LogLevel lvl, lazy bool cond, lazy S fmt, lazy T stuff) if (isSomeString!Str); These overloads always evaluate their first argument eagerly to determine the required logging level. Depending on it they may or may not evaluate their other arguments. This is not negotiable. 4. Replace defaultLogger with theLog. "Logger" is a word, but one that means "lumberjack" so it doesn't have the appropriate semantics. The use is generally acceptable as a nice play on words and as a disambiguator between the verb "to log" and the noun "log". When we actually want to talk about the current log in an application, we should, however, call it "the log". This is negotiable. 5. I was hoping for a resolution on throttling. However, now I realize that conditional logging plus throttling functions that return true once in a while should work acceptably well. Higher-order functions taking lambdas that log would also be a nice possibility. So... no request here. 6. I'm still hoping for RefCounted as the storage for the class backend. I realize users can do their own management but log objects are unlikely to contain cycles and other liabilities for reference counting, and at some point if we want to use reference counting where appropriate we got to start somewhere with a few solid precedents. This is negotiable, but I plan to fight for it.4) Any additional comments for author.Don't let any of the above discourage you. This is great work and is already one foot in. Let's get this done and done. Don't forget - it's all about Deutsche Gründlichkeit! Andrei
Jul 28 2014
On Tuesday, 29 July 2014 at 06:09:25 UTC, Andrei Alexandrescu wrote:No in current form. Yes assuming the fixes below are implemented....No. I also think any new module should sit in std.experimental for one release cycle.Clarification, just to be sure you got it right - right now we _only_ vote on inclusion into std.experimental, even if majority of voters will consider it Phobos-quality. Staging period of one release cycle is mandatory. That said - can you explain a bit more why you think it can't be included in std.experimental? (== think that it is fundamentally broken to the point it can't be even suggested for experiments) Most issues listed seem to be more related to actual Phobos inclusion.
Jul 28 2014
On 7/28/14, 11:46 PM, Dicebot wrote:On Tuesday, 29 July 2014 at 06:09:25 UTC, Andrei Alexandrescu wrote:I explained in the non-negotiable points. The point of keeping a module in std.experimental is watching for only minor tweaks. I think e.g. the names in the API is in need of solid change, which is easy to effect but affects callers quite a bit. -- AndreiNo in current form. Yes assuming the fixes below are implemented....No. I also think any new module should sit in std.experimental for one release cycle.Clarification, just to be sure you got it right - right now we _only_ vote on inclusion into std.experimental, even if majority of voters will consider it Phobos-quality. Staging period of one release cycle is mandatory. That said - can you explain a bit more why you think it can't be included in std.experimental? (== think that it is fundamentally broken to the point it can't be even suggested for experiments) Most issues listed seem to be more related to actual Phobos inclusion.
Jul 29 2014
On Tuesday, 29 July 2014 at 16:59:51 UTC, Andrei Alexandrescu wrote:The point of keeping a module in std.experimental is watching for only minor tweaks.I agree. For this reason, I also vote for "no" (1 as well as 2), as the current conditional logging support doubles the size of the API for shaving a grand total of 3 characters off the invocation in a rather infrequent use case. Cheers, David
Jul 29 2014
On Tuesday, 29 July 2014 at 06:09:25 UTC, Andrei Alexandrescu wrote:My vote is a qualified "yes" contingent upon fixes that I'll give detail on below. In the current form my vote is "no" seeing as the module makes a number of unforced tactical errors. Overall I think the goods are there, and are easy to put in acceptable form.Here's my list: 1. Minimal logging level must be selected statically in addition to the current dynamic selection. Static settings preclude dynamic settings. This is not negotiable.I'm not sure how you except log(LogLevel.xxxx, "Hello world") to be disabled at compile time if LogLevel.xxxx is a runtime value? Or do I misunderstood you? you can choose to disable name based logging like trace("Hello trace") at CT with the current release2. All logging code must be rigorously eliminated if below the static logging level. More precisely, there must be a front-end optimization that eliminates all code dedicated to a "lazy" variable that's not used by a generic function. This would be a fantastic redeeming of the "lazy" keyword, which has been of marginal utility until now. The challenge here is cooperating with someone on the compiler team to make sure that front-end improvement gets implemented, and writing unit tests that make sure there's no regression later. This is not negotiable.If you disabled one on the names logging functions at CT other prototypes will be used that have no lazy in it. You said that empty functions with lazy parameter are not optimized away. So there are no empty functions with lazy parameter if you disable these functions. As soon as the compiler can kill empty functions with lazy arguments this branching can be removed without any user code adjustment.3. The suffix notations must be replaced with overloads. The only acceptable suffix is "f" for formatting. Everything else must be achieved via overloads with the help of template constraints. Robert's answer http://goo.gl/FehDVh suggests he didn't consider using template constraints. We can't let that slip become a feature of the library for millenia to come. The overloads must be: // just log stuff log(T...)(lazy T stuff) if (!is(T[0] : const LogLevel)); // log with format logf(S, T...)(lazy S fmt, lazy T stuff) if (isSomeString!Str); // log conditional with format logf(S, T...)(lazy bool cond, lazy S fmt, lazy T stuff) if (isSomeString!Str); These three overloads should be repeated for all logging functions (info, trace etc). The functions don't evaluate their arguments if the respective log level is disabled. The following functions will NOT be repeated for all logging functions: // just log stuff at some level log(T...)(LogLevel lvl, lazy T stuff) if (!is(T[0] : const LogLevel)); // log with format logf(S, T...)(LogLevel lvl, lazy S fmt, lazy T stuff) if (isSomeString!Str); // log conditional with format logf(S, T...)(LogLevel lvl, lazy bool cond, lazy S fmt, lazy T stuff) if (isSomeString!Str); These overloads always evaluate their first argument eagerly to determine the required logging level. Depending on it they may or may not evaluate their other arguments. This is not negotiable.Overloads are implemented in the current version. They behave as you described.4. Replace defaultLogger with theLog. "Logger" is a word, but one that means "lumberjack" so it doesn't have the appropriate semantics. The use is generally acceptable as a nice play on words and as a disambiguator between the verb "to log" and the noun "log". When we actually want to talk about the current log in an application, we should, however, call it "the log". This is negotiable.I really don't care how a global Logger instance is called. Anyone else has an opinion on this? Otherwise Andrei wins.5. I was hoping for a resolution on throttling. However, now I realize that conditional logging plus throttling functions that return true once in a while should work acceptably well. Higher-order functions taking lambdas that log would also be a nice possibility. So... no request here.Creating a std.logger.conditions module is on my todo, std.logger.(stderr,stdout) will be cut because of being to noisy. I'm thinking of * anyN * anyNmillisec * firstN * ...6. I'm still hoping for RefCounted as the storage for the class backend. I realize users can do their own management but log objects are unlikely to contain cycles and other liabilities for reference counting, and at some point if we want to use reference counting where appropriate we got to start somewhere with a few solid precedents. This is negotiable, but I plan to fight for it.IMO something is wrong in the users code if the GC working on Logger instances is slowing the code done. The Logger instances properly stay around for the length of the programs execution. If you create Logger in a tight loop RC will properly slow you down as well.Hope this brings you closer to a "yes" Robert4) Any additional comments for author.Don't let any of the above discourage you. This is great work and is already one foot in. Let's get this done and done. Don't forget - it's all about Deutsche Gründlichkeit! Andrei
Jul 29 2014
On Tue, Jul 29, 2014 at 11:09:27PM +0000, Robert burner Schadek via Digitalmars-d wrote:On Tuesday, 29 July 2014 at 06:09:25 UTC, Andrei Alexandrescu wrote:[...][...] I propose 'stdlog'. T -- There's light at the end of the tunnel. It's the oncoming train.4. Replace defaultLogger with theLog. "Logger" is a word, but one that means "lumberjack" so it doesn't have the appropriate semantics. The use is generally acceptable as a nice play on words and as a disambiguator between the verb "to log" and the noun "log". When we actually want to talk about the current log in an application, we should, however, call it "the log". This is negotiable.I really don't care how a global Logger instance is called. Anyone else has an opinion on this? Otherwise Andrei wins.
Jul 29 2014
On 7/29/14, 4:16 PM, H. S. Teoh via Digitalmars-d wrote:On Tue, Jul 29, 2014 at 11:09:27PM +0000, Robert burner Schadek via Digitalmars-d wrote:I thought of the same but then rejected it - stdlog looks like offering the same interface as stdout and stderr. Nevertheless it's a sensible choice, too. -- AndreiOn Tuesday, 29 July 2014 at 06:09:25 UTC, Andrei Alexandrescu wrote:[...][...] I propose 'stdlog'.4. Replace defaultLogger with theLog. "Logger" is a word, but one that means "lumberjack" so it doesn't have the appropriate semantics. The use is generally acceptable as a nice play on words and as a disambiguator between the verb "to log" and the noun "log". When we actually want to talk about the current log in an application, we should, however, call it "the log". This is negotiable.I really don't care how a global Logger instance is called. Anyone else has an opinion on this? Otherwise Andrei wins.
Jul 29 2014
On Tue, Jul 29, 2014 at 04:55:04PM -0700, Andrei Alexandrescu via Digitalmars-d wrote:On 7/29/14, 4:16 PM, H. S. Teoh via Digitalmars-d wrote:I don't like 'theLog'. What about 'defaultLog'? T -- Never trust an operating system you don't have source for! -- Martin SchulzeOn Tue, Jul 29, 2014 at 11:09:27PM +0000, Robert burner Schadek via Digitalmars-d wrote:I thought of the same but then rejected it - stdlog looks like offering the same interface as stdout and stderr. Nevertheless it's a sensible choice, too. -- AndreiOn Tuesday, 29 July 2014 at 06:09:25 UTC, Andrei Alexandrescu wrote:[...][...] I propose 'stdlog'.4. Replace defaultLogger with theLog. "Logger" is a word, but one that means "lumberjack" so it doesn't have the appropriate semantics. The use is generally acceptable as a nice play on words and as a disambiguator between the verb "to log" and the noun "log". When we actually want to talk about the current log in an application, we should, however, call it "the log". This is negotiable.I really don't care how a global Logger instance is called. Anyone else has an opinion on this? Otherwise Andrei wins.
Jul 29 2014
On Wednesday, 30 July 2014 at 00:15:26 UTC, H. S. Teoh via Digitalmars-d wrote:On Tue, Jul 29, 2014 at 04:55:04PM -0700, Andrei Alexandrescu via Digitalmars-d wrote:+1 for !theLog. I actually like "dlog" because I hate typing but defaultLog would be fine. /uriOn 7/29/14, 4:16 PM, H. S. Teoh via Digitalmars-d wrote:I don't like 'theLog'. What about 'defaultLog'? TOn Tue, Jul 29, 2014 at 11:09:27PM +0000, Robert burner Schadek via Digitalmars-d wrote:I thought of the same but then rejected it - stdlog looks like offering the same interface as stdout and stderr. Nevertheless it's a sensible choice, too. -- AndreiOn Tuesday, 29 July 2014 at 06:09:25 UTC, Andrei Alexandrescu wrote:[...][...] I propose 'stdlog'.4. Replace defaultLogger with theLog. "Logger" is a word, but one that means "lumberjack" so it doesn't have the appropriate semantics. The use is generally acceptable as a nice play on words and as a disambiguator between the verb "to log" and the noun "log". When we actually want to talk about the current log in an application, we should, however, call it "the log". This is negotiable.I really don't care how a global Logger instance is called. Anyone else has an opinion on this? Otherwise Andrei wins.
Jul 29 2014
Am Wed, 30 Jul 2014 01:42:57 +0000 schrieb "uri" <email ether.com>:On Wednesday, 30 July 2014 at 00:15:26 UTC, H. S. Teoh via Digitalmars-d wrote:appLog/applogOn Tue, Jul 29, 2014 at 04:55:04PM -0700, Andrei Alexandrescu via Digitalmars-d wrote:+1 for !theLog. I actually like "dlog" because I hate typing but defaultLog would be fine. /uriOn 7/29/14, 4:16 PM, H. S. Teoh via Digitalmars-d wrote:I don't like 'theLog'. What about 'defaultLog'? TI propose 'stdlog'.I thought of the same but then rejected it - stdlog looks like offering the same interface as stdout and stderr. Nevertheless it's a sensible choice, too. -- Andrei
Aug 26 2014
On 7/29/14, 4:09 PM, Robert burner Schadek wrote:I'm not sure how you except log(LogLevel.xxxx, "Hello world") to be disabled at compile time if LogLevel.xxxx is a runtime value? Or do I misunderstood you? you can choose to disable name based logging like trace("Hello trace") at CT with the current releaseIn all likelihood I misunderstood you! Whenever a LogLevel is passed explicitly there's no static complete elimination possible as you mentioned. I now see a bunch of versions: DisableXxx (5 total) and DisableBelowXxx (5 total). That's fine if a bit out of character with the simplicity of the rest of the library.If you disabled one on the names logging functions at CT other prototypes will be used that have no lazy in it. You said that empty functions with lazy parameter are not optimized away. So there are no empty functions with lazy parameter if you disable these functions. As soon as the compiler can kill empty functions with lazy arguments this branching can be removed without any user code adjustment.No, they should stay lazy. The code of the lambdas is still generated, that's the main problem. As a matter of policy I'd rather push std.log and the compiler improvement together. Otherwise we push std.log and then nobody fixes the compiler, ever. We must put pressure on the compiler folks.Overloads are implemented in the current version. They behave as you described.Awesome!Prolly these are good outside of logger, they have wider applicability.5. I was hoping for a resolution on throttling. However, now I realize that conditional logging plus throttling functions that return true once in a while should work acceptably well. Higher-order functions taking lambdas that log would also be a nice possibility. So... no request here.Creating a std.logger.conditions module is on my todo, std.logger.(stderr,stdout) will be cut because of being to noisy. I'm thinking of * anyN * anyNmillisec * firstN * ...Agreed. I'm just saying... well what I said: RC should be an obvious default to reach for unless true GC is needed. Andrei6. I'm still hoping for RefCounted as the storage for the class backend. I realize users can do their own management but log objects are unlikely to contain cycles and other liabilities for reference counting, and at some point if we want to use reference counting where appropriate we got to start somewhere with a few solid precedents. This is negotiable, but I plan to fight for it.IMO something is wrong in the users code if the GC working on Logger instances is slowing the code done. The Logger instances properly stay around for the length of the programs execution. If you create Logger in a tight loop RC will properly slow you down as well.
Jul 29 2014
On Tuesday, 29 July 2014 at 23:09:28 UTC, Robert burner Schadek wrote:On Tuesday, 29 July 2014 at 06:09:25 UTC, Andrei Alexandrescu wrote:I don't see anything wrong with "logger". A "driver" is something that drives (a device), a "logger" is something that logs. Just "log" would be ok, too. Both are in common use, and are terms that I would use intuitively. "defaultLogger" or "currentLogger" might also be ok, but don't read as nicely. But please not "theLogger".4. Replace defaultLogger with theLog. "Logger" is a word, but one that means "lumberjack" so it doesn't have the appropriate semantics. The use is generally acceptable as a nice play on words and as a disambiguator between the verb "to log" and the noun "log". When we actually want to talk about the current log in an application, we should, however, call it "the log". This is negotiable.I really don't care how a global Logger instance is called. Anyone else has an opinion on this? Otherwise Andrei wins.
Jul 30 2014
"Marc Schütz" " wrote in message news:igznybcggsqgfhmmymrd forum.dlang.org...I don't see anything wrong with "logger". A "driver" is something that drives (a device), a "logger" is something that logs. Just "log" would be ok, too. Both are in common use, and are terms that I would use intuitively. "defaultLogger" or "currentLogger" might also be ok, but don't read as nicely. But please not "theLogger".I agree with this too. All of it.
Jul 30 2014
On Wednesday, 30 July 2014 at 12:01:21 UTC, Daniel Murphy wrote:"Marc Schütz" " wrote in message news:igznybcggsqgfhmmymrd forum.dlang.org...+1. theLog seems unintuitive to me. It's not like Logger is some kind of singleton, the global merely holds the default (!) instance. 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, DavidI don't see anything wrong with "logger". A "driver" is something that drives (a device), a "logger" is something that logs. Just "log" would be ok, too. Both are in common use, and are terms that I would use intuitively. "defaultLogger" or "currentLogger" might also be ok, but don't read as nicely. But please not "theLogger".I agree with this too. All of it.
Jul 30 2014
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, DavidIn addition: The setter property for the name of the logger together with the sorting of loggers by name and 'assumeSorted' will cause trouble.
Jul 30 2014
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?Wow, upon further code review I discovered that Logger actually overrides opCmp/opEquals to be based on the name (?!). This leads to the following gem: --- void main() { import std.logger.filelogger; auto a = new FileLogger("asdf", "w"); auto b = new FileLogger("qwer", "w"); assert(a == b); // WAT } --- Cheers, David
Jul 30 2014
On 7/30/14, 2:22 AM, "Marc Schütz" <schuetzm gmx.net>" wrote:On Tuesday, 29 July 2014 at 23:09:28 UTC, Robert burner Schadek wrote:Such logic doesn't apply to vocabularies. Is an "irater" someone who irates, a "messer" someone who creates a mess etc?On Tuesday, 29 July 2014 at 06:09:25 UTC, Andrei Alexandrescu wrote:I don't see anything wrong with "logger". A "driver" is something that drives (a device), a "logger" is something that logs.4. Replace defaultLogger with theLog. "Logger" is a word, but one that means "lumberjack" so it doesn't have the appropriate semantics. The use is generally acceptable as a nice play on words and as a disambiguator between the verb "to log" and the noun "log". When we actually want to talk about the current log in an application, we should, however, call it "the log". This is negotiable.I really don't care how a global Logger instance is called. Anyone else has an opinion on this? Otherwise Andrei wins.Just "log" would be ok, too. Both are in common use, and are terms that I would use intuitively. "defaultLogger" or "currentLogger" might also be ok, but don't read as nicely. But please not "theLogger".Sure not, it's theLog. I'm okay with stdlog. Andrei
Jul 30 2014
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.
Jul 30 2014
On 7/30/14, 8:16 AM, Kagamin wrote:On Wednesday, 30 July 2014 at 14:59:38 UTC, Andrei Alexandrescu wrote: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. AndreiSuch 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.
Jul 30 2014
"Andrei Alexandrescu" wrote in message news:lrb8dj$4cn$1 digitalmars.com...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.But the default log object is the tool you use to write things into the log! It's the secretary you yell things at from the other room, who then writes them down in the actual log (or logs (or nowhere)).
Jul 30 2014
On 7/30/14, 10:13 AM, Daniel Murphy wrote:"Andrei Alexandrescu" wrote in message news:lrb8dj$4cn$1 digitalmars.com...No, the way I see it is myLog.write("stuff"), i.e. it's me, the caller, who is doing the logging (i.e. I'm the logger), and myLog is the object of the action. Granted, things could be interpreted as in "I tell the logger to carry writing into some other log" but that becomes pop philosophy. By Occam's rule, just call the object a log, not a logger. -- AndreiYah 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.But the default log object is the tool you use to write things into the log! It's the secretary you yell things at from the other room, who then writes them down in the actual log (or logs (or nowhere)).
Jul 30 2014
"Andrei Alexandrescu" wrote in message news:lrbc50$78i$1 digitalmars.com...No, the way I see it is myLog.write("stuff"), i.e. it's me, the caller, who is doing the logging (i.e. I'm the logger), and myLog is the object of the action. Granted, things could be interpreted as in "I tell the logger to carry writing into some other log" but that becomes pop philosophy. By Occam's rule, just call the object a log, not a logger.It's subjective either way. Isn't language fun!
Jul 30 2014
On Wednesday, 30 July 2014 at 17:01:39 UTC, Andrei Alexandrescu wrote:So the appropriate name for the default log object is "defaultLog" not "defaultLogger", or "stdlog" not "stdlogger". The better choice is also shorter.I'm not going to join a discussion about the finer details of applying logic to natural language or the applicability of anthropomorphic analogies to log(ging forests of) messages, but let me point out that you should probably also argue for std.logger -> std.log and XyzLogger -> XyxLog to keep the names consistent. Cheers, David
Jul 30 2014
On Wednesday, 30 July 2014 at 17:01:39 UTC, Andrei Alexandrescu wrote:On 7/30/14, 8:16 AM, Kagamin wrote: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.On Wednesday, 30 July 2014 at 14:59:38 UTC, Andrei Alexandrescu wrote: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. AndreiSuch 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.
Jul 30 2014
On 7/30/14, 10:50 AM, linkrope wrote:On Wednesday, 30 July 2014 at 17:01:39 UTC, Andrei Alexandrescu wrote:But here we're discussing the name of the default log object... -- AndreiOn 7/30/14, 8:16 AM, Kagamin wrote: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.On Wednesday, 30 July 2014 at 14:59:38 UTC, Andrei Alexandrescu wrote: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. AndreiSuch 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.
Jul 30 2014
On Wednesday, 30 July 2014 at 18:08:12 UTC, Andrei Alexandrescu wrote:On 7/30/14, 10:50 AM, linkrope wrote: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");On Wednesday, 30 July 2014 at 17:01:39 UTC, Andrei Alexandrescu wrote:But here we're discussing the name of the default log object... -- AndreiOn 7/30/14, 8:16 AM, Kagamin wrote: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.On Wednesday, 30 July 2014 at 14:59:38 UTC, Andrei Alexandrescu wrote: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. AndreiSuch 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.
Jul 30 2014
On 7/30/14, 11:23 AM, linkrope wrote: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");Yah but then we have stuttering such as log.log("ehm") which is oddly the same as log("ehm"). -- Andrei
Jul 30 2014
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
Jul 31 2014
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:And with alias writef opCall; (from the previous std.log proposal) it could also be log("ehm");Yah but then we have stuttering such as log.log("ehm") which is oddly the same as log("ehm").log.write log.writef
Jul 31 2014
On Thursday, 31 July 2014 at 09:07:07 UTC, linkrope wrote:On Thursday, 31 July 2014 at 07:13:37 UTC, Kagamin wrote:log.note() log.say() What about dlog? dlog.note() dlog.log() dlog.say() It is short and it is D...On Wednesday, 30 July 2014 at 20:41:15 UTC, Andrei Alexandrescu wrote:And with alias writef opCall; (from the previous std.log proposal) it could also be log("ehm");Yah but then we have stuttering such as log.log("ehm") which is oddly the same as log("ehm").log.write log.writef
Jul 31 2014
On 7/31/14, 12:13 AM, Kagamin wrote:On Wednesday, 30 July 2014 at 20:41:15 UTC, Andrei Alexandrescu wrote:Then you have the globals write and writef which will compete with those in std.stdio. -- AndreiYah but then we have stuttering such as log.log("ehm") which is oddly the same as log("ehm").log.write log.writef
Jul 31 2014
On Thursday, 31 July 2014 at 15:41:40 UTC, Andrei Alexandrescu wrote:Then you have the globals write and writef which will compete with those in std.stdio. -- AndreiAren't they from different overload sets?
Aug 01 2014
On 8/1/14, 4:00 AM, Kagamin wrote:On Thursday, 31 July 2014 at 15:41:40 UTC, Andrei Alexandrescu wrote:Doesn't seem to me. They all accept e.g. one string. -- AndreiThen you have the globals write and writef which will compete with those in std.stdio. -- AndreiAren't they from different overload sets?
Aug 01 2014
On Friday, 1 August 2014 at 15:05:55 UTC, Andrei Alexandrescu wrote:On 8/1/14, 4:00 AM, Kagamin wrote:So what is the problem? We have module system to resolve that, do we?On Thursday, 31 July 2014 at 15:41:40 UTC, Andrei Alexandrescu wrote:Doesn't seem to me. They all accept e.g. one string. -- AndreiThen you have the globals write and writef which will compete with those in std.stdio. -- AndreiAren't they from different overload sets?
Aug 01 2014
On 8/1/14, 8:07 AM, Dicebot wrote:On Friday, 1 August 2014 at 15:05:55 UTC, Andrei Alexandrescu wrote:Yah but there's this inconvenience when people import two stdlib modules and then they need to qualify calls. I agree it's more of a matter of perception/user education. -- AndreiOn 8/1/14, 4:00 AM, Kagamin wrote:So what is the problem? We have module system to resolve that, do we?On Thursday, 31 July 2014 at 15:41:40 UTC, Andrei Alexandrescu wrote:Doesn't seem to me. They all accept e.g. one string. -- AndreiThen you have the globals write and writef which will compete with those in std.stdio. -- AndreiAren't they from different overload sets?
Aug 01 2014
On 08/01/2014 05:07 PM, Dicebot wrote:On Friday, 1 August 2014 at 15:05:55 UTC, Andrei Alexandrescu wrote:Exactly, that's the problem. They collide, so when import both the hijack protection will error. import std.stdio, std.log; write("foobar"); // matches both std.stdio.write and std.log.write It'd also make it more difficult to tell what `write("foobar")` does, which is unacceptable for such a fundamental operation.On 8/1/14, 4:00 AM, Kagamin wrote:So what is the problem? We have module system to resolve that, do we?On Thursday, 31 July 2014 at 15:41:40 UTC, Andrei Alexandrescu wrote:Doesn't seem to me. They all accept e.g. one string. -- AndreiThen you have the globals write and writef which will compete with those in std.stdio. -- AndreiAren't they from different overload sets?
Aug 01 2014
On 08/01/2014 05:31 PM, Martin Nowak wrote:Exactly, that's the problem. They collide, so when import both the hijack protection will error. import std.stdio, std.log; write("foobar"); // matches both std.stdio.write and std.log.write It'd also make it more difficult to tell what `write("foobar")` does, which is unacceptable for such a fundamental operation.We already have a similar issue with std.stdio.write and std.file.write that is fairly annoying.
Aug 01 2014
On Friday, 1 August 2014 at 15:31:39 UTC, Martin Nowak wrote:Exactly, that's the problem. They collide, so when import both the hijack protection will error. import std.stdio, std.log; write("foobar"); // matches both std.stdio.write and std.log.write It'd also make it more difficult to tell what `write("foobar")` does, which is unacceptable for such a fundamental operation.Solution is easy - don't do `import std.log` an don't recommend use to do it in docs, always use `import log = std.log`. This is how D module system is supposed to work. Right now there two conflicting statements in language docs: 1) namespaces are not needed, modules should work as replacement 2) usage of plain imports is encouraged Pretending that (1) is true and at the same time putting namespace workaround to the library is just lying to the programmers. Either we need to encourage programming style that works with D module system or admit it has completely failed. It is a problem not unique to std.logger
Aug 01 2014
"Dicebot" wrote in message news:slflceuaxmlsdsxzcsxc forum.dlang.org...Solution is easy - don't do `import std.log` an don't recommend use to do it in docs, always use `import log = std.log`. This is how D module system is supposed to work.It's easy, but it's not the easiest. There is a lot of value in having the easiest way to do something also be the right way.
Aug 01 2014
On Friday, 1 August 2014 at 16:18:26 UTC, Daniel Murphy wrote:"Dicebot" wrote in message news:slflceuaxmlsdsxzcsxc forum.dlang.org...I am afraid we don't have the right way in D then. Caring about cross-module name conflicts feels too much like plain C.Solution is easy - don't do `import std.log` an don't recommend use to do it in docs, always use `import log = std.log`. This is how D module system is supposed to work.It's easy, but it's not the easiest. There is a lot of value in having the easiest way to do something also be the right way.
Aug 01 2014
"Dicebot" wrote in message news:pnwgrcqfuhkzcaasatti forum.dlang.org...I am afraid we don't have the right way in D then. Caring about cross-module name conflicts feels too much like plain C.But with overloading! It isn't just about avoiding conflicts - if the function name is unique, you can tell what the code is doing without having to examine the context so closely. This is especially important for the standard library, because the time spent learning names can be reclaimed over multiple projects. This is a strength of C, although C goes way too far with forcing it.
Aug 01 2014
On Friday, 1 August 2014 at 17:06:24 UTC, Daniel Murphy wrote:"Dicebot" wrote in message news:pnwgrcqfuhkzcaasatti forum.dlang.org...If you find this important, you can always require renamed / static imports in your projects. On the contrary, if function name is already qualified with some redundant information, there is no simple way back other than aliasing all symbols from that module. I am convinced we are missing good style of using D import system, not good names.I am afraid we don't have the right way in D then. Caring about cross-module name conflicts feels too much like plain C.But with overloading! It isn't just about avoiding conflicts - if the function name is unique, you can tell what the code is doing without having to examine the context so closely. This is especially important for the standard library, because the time spent learning names can be reclaimed over multiple projects.This is a strength of C, although C goes way too far with forcing it.There are surprisingly many things I miss from C but manual name mangling is not in that list.
Aug 01 2014
On 8/1/14, 6:08 PM, Dicebot wrote:On Friday, 1 August 2014 at 17:06:24 UTC, Daniel Murphy wrote:To an extent I agree, but I have to side with the view that common artifacts in stdlib can cause quite some annoyance. I remember bug reports being made about clashing symbols between (I forgot exactly) std.string, std.regex, and std.algorithm. Clearly avoiding those clashes was all business as usual, but that doesn't mean we can't make things a tad better for standard library users. Andrei"Dicebot" wrote in message news:pnwgrcqfuhkzcaasatti forum.dlang.org...If you find this important, you can always require renamed / static imports in your projects. On the contrary, if function name is already qualified with some redundant information, there is no simple way back other than aliasing all symbols from that module. I am convinced we are missing good style of using D import system, not good names.I am afraid we don't have the right way in D then. Caring about cross-module name conflicts feels too much like plain C.But with overloading! It isn't just about avoiding conflicts - if the function name is unique, you can tell what the code is doing without having to examine the context so closely. This is especially important for the standard library, because the time spent learning names can be reclaimed over multiple projects.
Aug 01 2014
On 08/02/2014 03:19 AM, Andrei Alexandrescu wrote:Clearly avoiding those clashes was all business as usual,The newly introduced _private_ aliases would have possibly led to more clashes, aggravating the issue.
Aug 01 2014
"Dicebot" wrote in message news:aulaiptmiywxykqyhppt forum.dlang.org...There are surprisingly many things I miss from C but manual name mangling is not in that list.I don't like manual name mangling, but I like being able to look at a line of code and know exactly what it does. There are other factors, but this is an important one. I know using IDEs makes the cost of finding out what it actually does much lower, but it's a cost nonetheless.
Aug 02 2014
On Friday, 1 August 2014 at 15:31:39 UTC, Martin Nowak wrote:It'd also make it more difficult to tell what `write("foobar")` does, which is unacceptable for such a fundamental operation.Can you tell, what `log(1)` does?
Aug 01 2014
On 08/01/2014 07:10 PM, Kagamin wrote:On Friday, 1 August 2014 at 15:31:39 UTC, Martin Nowak wrote:It returns 0. No, wait...It'd also make it more difficult to tell what `write("foobar")` does, which is unacceptable for such a fundamental operation.Can you tell, what `log(1)` does?
Aug 01 2014
Can you tell, what `log(1)` does?Is there a irrefutable requirement to have a log function without explicit level? Do we lose anything if we just force every log call to have a level, and dump the plain 'log' method? Point people to use info if they don't care about the level, and you can clean things up considerably. As for voting: Qualified yes for std.experimental. If experimental is supposed to be 'done but not baked' then this would be a no vote, in favor of a few more iterations with the dub package (and pointing people to use it).
Aug 01 2014
On Friday, 1 August 2014 at 20:20:00 UTC, Jeremy Powers via Digitalmars-d wrote:As I understand, it's a defensive feature. There are things one wants in the log unconditionally, like OS version and program version. They can be logged at fatal level, but that's a workaround and looks confusing, and still can be filtered.Can you tell, what `log(1)` does?Is there a irrefutable requirement to have a log function without explicit level?
Aug 03 2014
Is there a[n] irrefutable requirement to have a log function withoutBelieve that's what the 'off' level is for, though it is confusingly named (off as in no filtering, not no logging). Maybe better called 'always'? I contend that having bare log methods without a specified level is a mis-feature. They may be useful as a shortcut when the desired level is unknown/irrelevant, but I don't believe what they add is worth the bother.explicit level?As I understand, it's a defensive feature. There are things one wants in the log unconditionally, like OS version and program version. They can be logged at fatal level, but that's a workaround and looks confusing, and still can be filtered.
Aug 04 2014
As I understand, it's a defensive feature. There are things one wants inLooking at the current version of the logger code, there is nothing that will always be logged - if the logging level (global or logger) is set to 'off' it will not log even if you call log() without a level. So a bit of clarifying around this may be desired.the log unconditionally, like OS version and program version. They can be logged at fatal level, but that's a workaround and looks confusing, and still can be filtered.Believe that's what the 'off' level is for, though it is confusingly named (off as in no filtering, not no logging). Maybe better called 'always'?I contend that having bare log methods without a specified level is a mis-feature. They may be useful as a shortcut when the desired level is unknown/irrelevant, but I don't believe what they add is worth the bother.Leaving this quote in, since it's my main point - I think not having a bare log() method is better than having one. Log levels are pretty basic to the idea of logging (as done here and most everywhere else), trying to ignore them just moves the complexity elsewhere.
Aug 04 2014
'always' or 'unfiltered' I'm fine with logl(LogLevel.max,...); I expect it to be used rarely. Well, maybe not logging anything when the level is set to 'off' makes sense, it just should work on any other level.
Aug 05 2014
On Wednesday, 30 July 2014 at 17:01:39 UTC, Andrei Alexandrescu wrote: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.Logging to a paper log is done directly without a logger. A similar approach would be to use just printf - logging can be done this way, but the reason for a logger is to let people not write to console directly, but use an intermediate component, which manages logging.
Jul 31 2014
On Wednesday, 30 July 2014 at 14:59:38 UTC, Andrei Alexandrescu wrote:On 7/30/14, 2:22 AM, "Marc Schütz" <schuetzm gmx.net>" wrote:Yes. It's called "derivation" in linguistics. It works in this case, because "-er" is a semi-productive suffix, which produces new nouns (called "nomina agentis") that refer to the "do-er", i.e. either a person, like the other meaning of "logger", or a tool, e.g. "box cutter". It is semi-productive, because as you noted, some derivations indeed sound odd and are almost never used. But this is getting way off-topic. My main point is that it's easy to understand, and it has lots of precedence in other software.On Tuesday, 29 July 2014 at 23:09:28 UTC, Robert burner Schadek wrote:Such logic doesn't apply to vocabularies. Is an "irater" someone who irates, a "messer" someone who creates a mess etc?On Tuesday, 29 July 2014 at 06:09:25 UTC, Andrei Alexandrescu wrote:I don't see anything wrong with "logger". A "driver" is something that drives (a device), a "logger" is something that logs.4. Replace defaultLogger with theLog. "Logger" is a word, but one that means "lumberjack" so it doesn't have the appropriate semantics. The use is generally acceptable as a nice play on words and as a disambiguator between the verb "to log" and the noun "log". When we actually want to talk about the current log in an application, we should, however, call it "the log". This is negotiable.I really don't care how a global Logger instance is called. Anyone else has an opinion on this? Otherwise Andrei wins.
Jul 30 2014
On 07/30/2014 01:09 AM, Robert burner Schadek wrote:I'm not sure how you except log(LogLevel.xxxx, "Hello world") to be disabled at compile time if LogLevel.xxxx is a runtime value? Or do I misunderstood you? you can choose to disable name based logging like trace("Hello trace") at CT with the current releaseHere is a proof of concept to achieve this. http://dpaste.dzfl.pl/95fb6a4e086d It works by creating a different type for each loglevel.
Jul 31 2014
On 08/01/2014 05:56 AM, Martin Nowak wrote:On 07/30/2014 01:09 AM, Robert burner Schadek wrote:Just checked tested this. static struct TestLogger { enum minLogLevel = LogLevel.error; void write(in LogEntry e) { _entries ~= e; } const(LogEntry)[] _entries; } void main() { TestLogger logger; logger.log(LogLevel.debug_, "foobar"); } The call logger.log(LogLevel.debug_) can be completely removed by the compiler. The delegates for the lazy parameters are still generated though. Either fixing [`--gc-sections`](https://issues.dlang.org/show_bug.cgi?id=879) or adding [LTO](https://github.com/ldc-developers/ldc/issues/693) would help. Also dmd (but not LDC) has a [bug](https://issues.dlang.org/show_bug.cgi?id=8615) where it still adds a few instructions to pass the delegate (even though the function is never called). So I think it's an appropriate solution to the problem. http://dpaste.dzfl.pl/95fb6a4e086dI'm not sure how you except log(LogLevel.xxxx, "Hello world") to be disabled at compile time if LogLevel.xxxx is a runtime value? Or do I misunderstood you? you can choose to disable name based logging like trace("Hello trace") at CT with the current releaseHere is a proof of concept to achieve this. http://dpaste.dzfl.pl/95fb6a4e086d It works by creating a different type for each loglevel.
Aug 01 2014
On Tuesday, 29 July 2014 at 06:09:25 UTC, Andrei Alexandrescu wrote:4. Replace defaultLogger with theLog. "Logger" is a word, but one that means "lumberjack" so it doesn't have the appropriate semantics. The use is generally acceptable as a nice play on words and as a disambiguator between the verb "to log" and the noun "log". When we actually want to talk about the current log in an application, we should, however, call it "the log". This is negotiable.FWIW: https://www.google.com/search?q=logger Here's the results I see: 8 results related to programming and log files 1 Wikipedia disambiguation page 1 sports-related result ("La Crosse Loggers")
Aug 31 2014
Dne 29.7.2014 7:11, Dicebot via Digitalmars-d napsal(a):(sorry for being a bit late, was distracted) std.logger proposal by Robert Schadek enters voting period which will last two weeks starting from now. Discussion thread : http://forum.dlang.org/post/zhvmkbahrqtgkptdlcvh forum.dlang.org This voting will be somewhat different from previous ones because it will be done with std.experimental in mind. Because of that please reply with a bit more structured votes: 1) Yes / No for inclusion into std.experimental At this point please consider if module has functionality you want to see in standard library in general and if implementation is not fundamentally broken. This is a simple sanity check.Yes. The API is sane and the design has withstood a lot of relevant criticism as well as bikeshedding. Although, I do not really like log function suffixes and would prefer overloads.2) Yes / No for inclusion into Phobos in its current state This is where you should summarize your concerns raised during review if there are any and make decision if existing API / architecture are promising enough to be set in stone via Phobos inclusion.No. There were a lot of changes during the review process. The module should IMO go to experimental to have some time to take care of all those small things as well as to get (hopefully) some larger adoption.3) If you have answered "No" for (2) : list of mandatory changes that are needed to make you vote "Yes"For me it is the stay in std.experimental and seeing that nobody is pressing for another api changes (like Andrei is doing now).4) Any additional comments for author.Great work and some great patience you have displayed in the process. Thank you!
Jul 28 2014
On Tuesday, 29 July 2014 at 05:11:33 UTC, Dicebot wrote:1) Yes / No for inclusion into std.experimentalYes. It's ready for an official stamp.2) Yes / No for inclusion into Phobos in its current stateNo. Full advantage should be taken of the std.experimental time.3) If you have answered "No" for (2) : list of mandatory changes that are needed to make you vote "Yes"Nothing new here, it's been covered by others. If I had to pick out something: Using overloads properly is a clear improvement step that must be taken for this to be considered phobos quality.
Jul 29 2014
1) Yes / No for inclusion into std.experimentalYes2) Yes / No for inclusion into Phobos in its current stateNo3) If you have answered "No" for (2) : list of mandatory changes that are needed to make you vote "Yes"I can't say Yes until I've actually used it.4) Any additional comments for author.None for the author as I detailed my concerns in Github, though I should apologize for being very lax about participating (RL has been busy). However, I wanted to address the suffix notation as I suggested it. What I was going for was consistency with the write/writef method signatures to keep things consistent. I felt it would be good to make the two similar since they do similar things. My suggestion for conditional versions, logc and logcf, I believe are the ones causing some heartburn. If you look at how write works, what does this mean? write(a < b, "some message"); Am I writing conditionally or am I writing out something like "truesome message"? In phobos, it is the latter. To have consistency, we can't simply make the first parameter be a condition as it would prevent us from doing something like this: log(canFind("foobar", "bar")); Second, the way I look at it, you can read the methods like this: write - write writef - write formatted log - log logf - log formatted logc - log conditionally logcf - log conditionally and formatted Having that english-like meaning I think will make it easier to recognize what's being done. tl;dr I proposed having the log interface consistent with the write interface (from a parameter standpoint) and suggested the "c" suffix to make it clear that conditional logging is being performed vs. the first parameter being a boolean that's part of the log message.
Jul 29 2014
maybe we should have made a vote for logc vs. log(bool) first I think we gone full circle ulong.max times by now ;-)
Jul 29 2014
On Tuesday, 29 July 2014 at 12:18:31 UTC, Robert burner Schadek wrote:maybe we should have made a vote for logc vs. log(bool) first I think we gone full circle ulong.max times by now ;-)This shouldn't affect inclusion to std.experimental and can be done at any moment
Jul 29 2014
On 7/29/14, 5:23 AM, Dicebot wrote:On Tuesday, 29 July 2014 at 12:18:31 UTC, Robert burner Schadek wrote:NO. We put something in std.experimental when we can't imagine what other work is to be done on the module. (Inevitably a little more work is prompted by usage, which is the point of it all.) We don't put in std.experimental stuff that has already a known backlog of work to do. Andreimaybe we should have made a vote for logc vs. log(bool) first I think we gone full circle ulong.max times by now ;-)This shouldn't affect inclusion to std.experimental and can be done at any moment
Jul 29 2014
On Tuesday, 29 July 2014 at 17:15:22 UTC, Andrei Alexandrescu wrote:NO. We put something in std.experimental when we can't imagine what other work is to be done on the module. (Inevitably a little more work is prompted by usage, which is the point of it all.) We don't put in std.experimental stuff that has already a known backlog of work to do. AndreiSpawned separate discussion thread : http://forum.dlang.org/post/icumpyexlsneievlmfex forum.dlang.org
Jul 29 2014
On 7/29/14, 5:18 AM, Robert burner Schadek wrote:maybe we should have made a vote for logc vs. log(bool) first I think we gone full circle ulong.max times by now ;-)My understanding is the entire prefix-letter approach was based on an oversight. Andrei
Jul 29 2014
On 7/29/14, 10:16 AM, Andrei Alexandrescu wrote:On 7/29/14, 5:18 AM, Robert burner Schadek wrote:s/prefix/suffix/maybe we should have made a vote for logc vs. log(bool) first I think we gone full circle ulong.max times by now ;-)My understanding is the entire prefix-letter approach was based on an oversight. Andrei
Jul 29 2014
On Tuesday, 29 July 2014 at 17:20:58 UTC, Andrei Alexandrescu wrote: I should have the overload approach done by tonight
Jul 29 2014
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 tonightHave 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.
Jul 29 2014
On Tuesday, 29 July 2014 at 22:15:18 UTC, linkrope wrote: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.of course, because you are doing much less
Jul 29 2014
On 7/29/14, 3:25 PM, Robert burner Schadek wrote:On Tuesday, 29 July 2014 at 22:15:18 UTC, linkrope wrote:The idea would be to push the static ifs from inside the function into the template constraints. -- AndreiHave 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.of course, because you are doing much less
Jul 29 2014
Second, the way I look at it, you can read the methods like this: write - write writef - write formatted log - log logf - log formatted logc - log conditionally logcf - log conditionally and formattedAndrei is Romanian; not Hungarian. And a Romanian is AFAIK also not a reverse Hungarian. So no need to arouse him by proposing a Hungarian Api. :) better being concise and precise.
Jul 29 2014
On Tuesday, 29 July 2014 at 05:11:33 UTC, Dicebot wrote:1) Yes / No for inclusion into std.experimentalYes, absolutely.2) Yes / No for inclusion into Phobos in its current stateNot yet.3) If you have answered "No" for (2) : list of mandatory changes that are needed to make you vote "Yes"As far as I undestood, there's no way right now to do logging without using the GC. And that means it is currently impossible to log inside destructor calls. That is a blocker in my book.4) Any additional comments for author.No matter the changes that might be applied to reduce suffix notation, I would love to retain the ability to do conditional unformatted logging.
Jul 29 2014
On Tue, 29 Jul 2014 05:11:31 +0000, Dicebot wrote:1) Yes / No for inclusion into std.experimentalYes2) Yes / No for inclusion into Phobos in its current stateNo see notes in (3)3) If you have answered "No" for (2) : list of mandatory changes that are needed to make you vote "Yes"We need to hammer out how this will work inside libraries. If my app is using multiple libraries I need to know I have full control of how they log and where (), and if I write libraries I need to include logging that will not affect performance or added dependencies. I like the idea of a standard interface for D logging. Other logging implementations should be able to plug into the interface without having to inherit from std.log.Logger (single inheritance issue). I would like to see conditional logging as part of the interface, or in the documentation show how we can achieve that with stdlib in a clean and simple way. Logger should include a shared Logger, or include it in the interface for outside libraries to handle the implementation. There will be libraries that thread internally and will need to support shared logging.4) Any additional comments for author.Awesome work so far. Getting this "right" is I huge pain, and I applaud you going through this.
Jul 29 2014
Awesome work so far. Getting this "right" is I huge pain, and I applaud you going through this.I should have said this as well. Regardless, I second this statement as this is probably the thing I'm looking forward to the most when it comes to additions to the standard library.
Jul 29 2014
On Tuesday, 29 July 2014 at 05:11:33 UTC, Dicebot wrote:(sorry for being a bit late, was distracted) std.logger proposal by Robert Schadek enters voting period which will last two weeks starting from now. Discussion thread : http://forum.dlang.org/post/zhvmkbahrqtgkptdlcvh forum.dlang.org This voting will be somewhat different from previous ones because it will be done with std.experimental in mind. Because of that please reply with a bit more structured votes: 1) Yes / No for inclusion into std.experimentalYes.At this point please consider if module has functionality you want to see in standard library in general and if implementation is not fundamentally broken. This is a simple sanity check. 2) Yes / No for inclusion into Phobos in its current stateYes. A lot of reusable components need warnings (hence: logging).This is where you should summarize your concerns raised during review if there are any and make decision if existing API / architecture are promising enough to be set in stone via Phobos inclusion. 3) If you have answered "No" for (2) : list of mandatory changes that are needed to make you vote "Yes" 4) Any additional comments for author.Thanks.
Jul 29 2014
Yes, assuming Andrei's non-negotiable issues are addressed first.
Jul 29 2014
On 07/29/2014 07:11 AM, Dicebot wrote:1) Yes / No for inclusion into std.experimental At this point please consider if module has functionality you want to see in standard library in general and if implementation is not fundamentally broken. This is a simple sanity check.Not yet2) Yes / No for inclusion into Phobos in its current stateNo, as much as I'd like to have logging facilities in phobos, there are too many outstanding issues.This is where you should summarize your concerns raised during review if there are any and make decision if existing API / architecture are promising enough to be set in stone via Phobos inclusion. 3) If you have answered "No" for (2) : list of mandatory changes that are needed to make you vote "Yes"Get rid of the 8 different suffixes. I only see the need for log and logf, why is the rest needed? log -> log(lazy Args args); logl -> log(LogLevel, lazy Args args); logf -> logf(string fmt, lazy Args args); loglf -> logf(LogLevel, string fmt, lazy Args args); logc -> if (cond) log(lazy Args args); loglc -> if (cond) log(LogLevel, lazy Args args); logcf -> if (cond) log(string fmt, lazy Args); loglcf -> if (cond) log(LogLevel, string fmt, lazy Args); You cannot use version identifiers to selectively disable functionality or people would have to compile their own phobos library for every set of version combinations. Support duck-typing for the log functions. Logger should be a concept and log functions should be free-standing UFCS functions that take any `isLogger!T`. To support a global `defaultLog` variable, you could add a Logger interface and a loggerObject shim. See http://dlang.org/phobos/std_range.html#inputRangeObject for this a pattern. The code could be consolidated and some classes could go. This would probably result in 1-2KLOC, so this could be a single module instead of a package.4) Any additional comments for author. Please separate (3) from (4) in some obvious fashion to make it possible for author to prioritize of feedback. Please use linked thread for discussions and only post vote + summary here. Currently only answer for (1) affects the voting outcome. Other answers are necessary to eventually prepare std.logger for second voting during beta period of some future release (for actual inclusion into Phobos). If you have any comments / proposals about actual voting procedure or review process please create separate thread. Go ahead ;)
Jul 31 2014
On 7/31/14, 7:19 PM, Martin Nowak wrote:You cannot use version identifiers to selectively disable functionality or people would have to compile their own phobos library for every set of version combinations.Wait, doesn't code work with the version chosen by the user? -- Andrei
Jul 31 2014
On 08/01/2014 04:31 AM, Andrei Alexandrescu wrote:On 7/31/14, 7:19 PM, Martin Nowak wrote:Well phobos as a library is precompiled, so the versions used to compile phobos will be relevant, not the ones in client code. For templated functions version identifier will "leak" from client code into the library, because technically they are instantiated by the client code. Also the version identifiers of client code determine which declarations you see. Relying on this would be a constant source of bugs. I did proof-of-concept yesterday using type tags and template constraints to statically disable certain log levels. It also has some drawbacks because LogLevel is no longer a plain enum, but it's more appropriate than version identifiers. http://forum.dlang.org/post/lrf362$tkn$1 digitalmars.comYou cannot use version identifiers to selectively disable functionality or people would have to compile their own phobos library for every set of version combinations.Wait, doesn't code work with the version chosen by the user? -- Andrei
Aug 01 2014
On 8/1/14, 8:52 AM, Martin Nowak wrote:On 08/01/2014 04:31 AM, Andrei Alexandrescu wrote:Oh I hadn't realized that. Thanks! That strengthens my opinion that more work is needed on the library before inclusion in std.experimental. -- AndreiOn 7/31/14, 7:19 PM, Martin Nowak wrote:Well phobos as a library is precompiled, so the versions used to compile phobos will be relevant, not the ones in client code. For templated functions version identifier will "leak" from client code into the library, because technically they are instantiated by the client code. Also the version identifiers of client code determine which declarations you see. Relying on this would be a constant source of bugs. I did proof-of-concept yesterday using type tags and template constraints to statically disable certain log levels. It also has some drawbacks because LogLevel is no longer a plain enum, but it's more appropriate than version identifiers. http://forum.dlang.org/post/lrf362$tkn$1 digitalmars.comYou cannot use version identifiers to selectively disable functionality or people would have to compile their own phobos library for every set of version combinations.Wait, doesn't code work with the version chosen by the user? -- Andrei
Aug 01 2014
On 8/1/14, 9:36 AM, Andrei Alexandrescu wrote:Oh I hadn't realized that. Thanks! That strengthens my opinion that more work is needed on the library before inclusion in std.experimental.To clarify: I'm very strongly opposed to a design that requires rebuilding Phobos (or relying on different pre-built versions) for different logging levels. That's just unacceptable. User code must be able to set logging levels by just passing flags to their own builds. Andrei
Aug 01 2014
Am Fri, 01 Aug 2014 09:43:32 -0700 schrieb Andrei Alexandrescu <SeeWebsiteForEmail erdani.org>:On 8/1/14, 9:36 AM, Andrei Alexandrescu wrote:It's kinda awkward how complicated the D solutions are compared to C/C++ with the preprocessor. The only simple way in D seems to be using string mixins, but these look ugly on the user side.Oh I hadn't realized that. Thanks! That strengthens my opinion that more work is needed on the library before inclusion in std.experimental.To clarify: I'm very strongly opposed to a design that requires rebuilding Phobos (or relying on different pre-built versions) for different logging levels. That's just unacceptable. User code must be able to set logging levels by just passing flags to their own builds. Andrei
Aug 01 2014
On Friday, 1 August 2014 at 16:43:32 UTC, Andrei Alexandrescu wrote:On 8/1/14, 9:36 AM, Andrei Alexandrescu wrote:Must be able, but should it be the only possible way?Oh I hadn't realized that. Thanks! That strengthens my opinion that more work is needed on the library before inclusion in std.experimental.To clarify: I'm very strongly opposed to a design that requires rebuilding Phobos (or relying on different pre-built versions) for different logging levels. That's just unacceptable. User code must be able to set logging levels by just passing flags to their own builds.
Aug 01 2014
On 8/1/14, 10:23 AM, Kagamin wrote:On Friday, 1 August 2014 at 16:43:32 UTC, Andrei Alexandrescu wrote:Other ways would be also nice, but the primary use case is the user chooses the static logging level during build. -- AndreiOn 8/1/14, 9:36 AM, Andrei Alexandrescu wrote:Must be able, but should it be the only possible way?Oh I hadn't realized that. Thanks! That strengthens my opinion that more work is needed on the library before inclusion in std.experimental.To clarify: I'm very strongly opposed to a design that requires rebuilding Phobos (or relying on different pre-built versions) for different logging levels. That's just unacceptable. User code must be able to set logging levels by just passing flags to their own builds.
Aug 01 2014
On Friday, 1 August 2014 at 15:52:30 UTC, Martin Nowak wrote:Well phobos as a library is precompiled, so the versions used to compile phobos will be relevant, not the ones in client code. For templated functions version identifier will "leak" from client code into the library, because technically they are instantiated by the client code.could you elaborate please? Currently I use the version statements in two template functions. I'm not sure why one would brand this negatively as a leak into the library.Also the version identifiers of client code determine which declarations you see. Relying on this would be a constant source of bugs.could you elaborate please?I did proof-of-concept yesterday using type tags and template constraints to statically disable certain log levels. It also has some drawbacks because LogLevel is no longer a plain enum, but it's more appropriate than version identifiers. http://forum.dlang.org/post/lrf362$tkn$1 digitalmars.comThank you for taking the time, but I found several conceptional problems with that POC. The worst being that if I make the LogLevel inside the TestLogger anything other than a enum it fails, as it is used in the template constraint. That would mean the LogLevel is fixed at CT.
Aug 08 2014
On Friday, 8 August 2014 at 09:16:11 UTC, Robert burner Schadek wrote:could you elaborate please? Currently I use the version statements in two template functions. I'm not sure why one would brand this negatively as a leak into the library.For example we don't reinstatiate templates if they are instantiated in an imported module. But that module might have been compiled with different settings.Thank you for taking the time, but I found several conceptional problems with that POC. The worst being that if I make the LogLevel inside the TestLogger anything other than a enum it fails, as it is used in the template constraint. That would mean the LogLevel is fixed at CT.Well if your test logger only knows it's log level at runtime, then you obviously can do the comparison only at runtime. You can solve this by checking whether minLogLevel is a compile time constant in the log constraints adding another overload for runtime configurable log levels.
Oct 24 2014
Voting ends tomorrow, summary post may get delayed for a few days though.
Aug 10 2014
thank you Dicebot for the work. I thought I give a quick update. * The interface now works on overloads with template constraints. * The internal api has been split in logHeader, logMsgPart and finishLogMsg (writeLogMsg) can still be used * StdIOLogger and StdErrLogger are replaced by FileLogger(stdout|stderr) * FileLogger take std.stdio.File as parameter for the ctor, though files can be closed on scope exit * FileLogger flush after logging * new DataTime formatter to output range (placeholder until std.datetime comes up with something) * fixed all spelling mistakes given in the review * more documentation (introduced new spelling mistakes ;-) review please) * ArrayLogger and MultiLogger use same std.container.Array based base class * More stuff I forgot about please review and let us get this thing moving
Aug 17 2014
On Sunday, 17 August 2014 at 12:16:38 UTC, Robert burner Schadek wrote:thank you Dicebot for the work. I thought I give a quick update. * The interface now works on overloads with template constraints. * The internal api has been split in logHeader, logMsgPart and finishLogMsg (writeLogMsg) can still be used * StdIOLogger and StdErrLogger are replaced by FileLogger(stdout|stderr) * FileLogger take std.stdio.File as parameter for the ctor, though files can be closed on scope exit * FileLogger flush after logging * new DataTime formatter to output range (placeholder until std.datetime comes up with something) * fixed all spelling mistakes given in the review * more documentation (introduced new spelling mistakes ;-) review please) * ArrayLogger and MultiLogger use same std.container.Array based base class * More stuff I forgot about please review and let us get this thing movingEventually I am going to go through the list of requirements from voting and current implementation and highlight any differences but it will take some time.
Aug 18 2014
On 8/17/14, 5:16 AM, Robert burner Schadek wrote:thank you Dicebot for the work. I thought I give a quick update. * The interface now works on overloads with template constraints. * The internal api has been split in logHeader, logMsgPart and finishLogMsg (writeLogMsg) can still be used * StdIOLogger and StdErrLogger are replaced by FileLogger(stdout|stderr) * FileLogger take std.stdio.File as parameter for the ctor, though files can be closed on scope exit * FileLogger flush after logging * new DataTime formatter to output range (placeholder until std.datetime comes up with something) * fixed all spelling mistakes given in the review * more documentation (introduced new spelling mistakes ;-) review please) * ArrayLogger and MultiLogger use same std.container.Array based base class * More stuff I forgot about please review and let us get this thing movingThis is very promising! Has the versioning issue been solved? I.e. we want the user code to choose the static logging level, not distribute five versions of Phobos. Andrei
Aug 18 2014
On Tuesday, 19 August 2014 at 02:26:24 UTC, Andrei Alexandrescu wrote:This is very promising! Has the versioning issue been solved? I.e. we want the user code to choose the static logging level, not distribute five versions of Phobos.There is now a template function with version statements inside that returns a bool that is used in an static if inside the templates that implement the log calls with explicit LogLevel. As the version statements get evaluated at CT of the log call from the user code only one version of Phobos is required. And you can disable all five LogLevel individual.
Aug 19 2014
On 8/19/14, 2:44 AM, Robert burner Schadek wrote:On Tuesday, 19 August 2014 at 02:26:24 UTC, Andrei Alexandrescu wrote:This is great, thanks. Not only this will be a good thing for std.logger, but it will set a precedent for new similar libraries without an explosion in distributions. We need some unittests to ensure that kind of stuff I guess. AndreiThis is very promising! Has the versioning issue been solved? I.e. we want the user code to choose the static logging level, not distribute five versions of Phobos.There is now a template function with version statements inside that returns a bool that is used in an static if inside the templates that implement the log calls with explicit LogLevel. As the version statements get evaluated at CT of the log call from the user code only one version of Phobos is required. And you can disable all five LogLevel individual.
Aug 19 2014
We need some unittests to ensure that kind of stuff I guess.I guess I have to freshen up my dmd compilation flow knowledge. I'm not use how to test version = DisableTrace; in std.logger.core and not disable user code trace logging with it. version(unittest) { version = DisableTrace; } will also not help. Maybe the non forward reference part does it!? Any suggestions?
Aug 19 2014
- Regarding i18n: I think you should avoid using natural language in strings or keep all such strings in a common file for all of phobos. - I am sceptical to the use of macro style mixins. It makes the code less transparent and less maintainable. - Having so many ways to call the log functions makes automatic search and replace difficult.
Aug 20 2014
On Wednesday, 20 August 2014 at 13:54:29 UTC, Ola Fosheim Grøstad wrote:- Regarding i18n: I think you should avoid using natural language in strings or keep all such strings in a common file for all of phobos.example, please?- I am sceptical to the use of macro style mixins. It makes the code less transparent and less maintainable.grep -R "mixin" std/experimental/logger | wc -l 0- Having so many ways to call the log functions makes automatic search and replace difficult.It uses overloads now ------------------------ BTW: * move std.logger to std.experimental.logger * the github project has unittests for the version statements (all pass) whats next?
Aug 26 2014
On 8/26/14, 8:44 AM, Robert burner Schadek wrote:whats next?One more round of reviews and let's merge to experimental if all good. Andrei
Aug 26 2014
On Tuesday, 26 August 2014 at 15:44:19 UTC, Robert burner Schadek wrote:BTW: * move std.logger to std.experimental.logger * the github project has unittests for the version statements (all pass) whats next?I will compare changelist against list of requirements from voters this weekend and if all seems to be addressed will start a new round of review/voting.
Aug 26 2014
Am Tue, 26 Aug 2014 18:23:30 +0000 schrieb "Dicebot" <public dicebot.lv>:On Tuesday, 26 August 2014 at 15:44:19 UTC, Robert burner Schadek wrote:Someone else mentioned it before: Logging in destructors would be a requirement for me, too. Thanks to the GC we usually don't release memory in them, but "foreign" resources like e.g. hardware audio playback buffers would typically handled in a dtor. I see two ways which both require logging: 1) Dtor calls a C function to release the resource, which may return an error code, that you want to log. You keep the program running since if all else fails you could still reinitialize the audio device, thereby releasing all buffers. 2) If waiting for the GC to eventually call the dtor is not an option because the resource is very limited, you require the user to call some .release/.close method. If in the dtor the resource is still "open", you log something like "WARNING: Destructor called, but audio buffer still attached. Call .close() on the last reference." As much as I see this as non-negotiable, (chancellor Merkel would have said "alternativlos",) I know it would currently require the whole log system to be nothrow nogc and we may not want to wait till allocating and throwing is allowed during GC sweeps, before we get std.log. -- MarcoBTW: * move std.logger to std.experimental.logger * the github project has unittests for the version statements (all pass) whats next?I will compare changelist against list of requirements from voters this weekend and if all seems to be addressed will start a new round of review/voting.
Aug 26 2014
On Tuesday, 26 August 2014 at 19:39:26 UTC, Marco Leise wrote:As much as I see this as non-negotiable, (chancellor Merkel would have said "alternativlos",) I know it would currently require the whole log system to be nothrow nogc and we may not want to wait till allocating and throwing is allowed during GC sweeps, before we get std.log.nothrow I get, but nothrow in dtors is a much wider topic (please open a new thread if you want to discuss this) and see my example to hack around it. but no nogc should be no problem as long as you use a Logger that doesn't allocate for logging, as for example FileLogger. And even than, what is the problem with no nogc logging in dtors? -------------- class Foo { ~this() { try { log("Foo"); // log to file } catch(Exception e) {} } } --------------
Aug 26 2014
Am Tue, 26 Aug 2014 20:59:57 +0000 schrieb "Robert burner Schadek" <rburners gmail.com>:nothrow I get, but nothrow in dtors is a much wider topic (please open a new thread if you want to discuss this) and see my example to hack around it.You are right.but no nogc should be no problem as long as you use a Logger that doesn't allocate for logging, as for example FileLogger. And even than, what is the problem with no nogc logging in dtors? -------------- class Foo { ~this() { try { log("Foo"); // log to file } catch(Exception e) {} } } --------------As far as I know, exactly this is not possible with the current GC implementation. The exception you catch there has just been allocated somewhere deeper in the log function. But all GC allocations in a GC invoked dtor cause MemoryErrors and program abortion/crashes. :( In a perfect world I'd imagine you can set up a fallback logger. So if the disk is full an exception is thrown by e.g. std.stdio.File, which is passed as an error level log message to the fallback logger, which might write to stderr: "ERROR: Could not write the following message to logXYZ: <message> The reason was: Disk full" -- Marco
Aug 26 2014
On Wednesday, 27 August 2014 at 00:09:15 UTC, Marco Leise wrote:As far as I know, exactly this is not possible with the current GC implementation. The exception you catch there has just been allocated somewhere deeper in the log function. But all GC allocations in a GC invoked dtor cause MemoryErrors and program abortion/crashes. :( In a perfect world I'd imagine you can set up a fallback logger. So if the disk is full an exception is thrown by e.g. std.stdio.File, which is passed as an error level log message to the fallback logger, which might write to stderr: "ERROR: Could not write the following message to logXYZ: <message> The reason was: Disk full"I don't think it will help either. The very moment exception is allocated inside std.stdio.File your program will crash, it won't get to fallback. Only solution is to implement your logger as nothrow thing by using only C functions internally instead of std.stdio - something that feels overly limited for a general use case. I really think this is the case where you should roll your own FileNoThrowingLogger and go with it. In a long term this is something much better to be fixed in GC implementation than constantly hacked in stdlib modules.
Aug 26 2014
Am Wed, 27 Aug 2014 01:09:21 +0000 schrieb "Dicebot" <public dicebot.lv>:On Wednesday, 27 August 2014 at 00:09:15 UTC, Marco Leise wrote:Exactly, I just needed someone else to speak it out. :)As far as I know, exactly this is not possible with the current GC implementation. The exception you catch there has just been allocated somewhere deeper in the log function. But all GC allocations in a GC invoked dtor cause MemoryErrors and program abortion/crashes. :( In a perfect world I'd imagine you can set up a fallback logger. So if the disk is full an exception is thrown by e.g. std.stdio.File, which is passed as an error level log message to the fallback logger, which might write to stderr: "ERROR: Could not write the following message to logXYZ: <message> The reason was: Disk full"I don't think it will help either. The very moment exception is allocated inside std.stdio.File your program will crash, it won't get to fallback. Only solution is to implement your logger as nothrow thing by using only C functions internally instead of std.stdio - something that feels overly limited for a general use case.I really think this is the case where you should roll your own FileNoThrowingLogger and go with it.*Me* or everyone who needs to log something in a dtor?In a long term this is something much better to be fixed in GC implementation than constantly hacked in stdlib modules.Or is this maybe the other language change (besides not generating code for unused lambdas) that should be pushed with std.log, because otherwise it will never be solved ? I don't know, but no logging in dtors is a serious and hard to sell limitation. Not the author's fault though. -- Marco
Aug 26 2014
On Wednesday, 27 August 2014 at 06:14:10 UTC, Marco Leise wrote:I really believe that necessity to log something in dtor is currently an indicator of design issues in the application. D class destructors are unreliable to the point of being almost useless, I'd be very careful about actually caring if those run at all.I really think this is the case where you should roll your own FileNoThrowingLogger and go with it.*Me* or everyone who needs to log something in a dtor?I agree that current situation is bad but I disagree that std.log is a proper place to solve it. It is a part of much bigger issue and adding few local workarounds does not make situation much better.In a long term this is something much better to be fixed in GC implementation than constantly hacked in stdlib modules.Or is this maybe the other language change (besides not generating code for unused lambdas) that should be pushed with std.log, because otherwise it will never be solved ? I don't know, but no logging in dtors is a serious and hard to sell limitation. Not the author's fault though.
Aug 28 2014
On Tuesday, 26 August 2014 at 19:39:26 UTC, Marco Leise wrote:Am Tue, 26 Aug 2014 18:23:30 +0000 schrieb "Dicebot" <public dicebot.lv>:On Tuesday, 26 August 2014 at 15:44:19 UTC, Robert burner Schadek wrote:BTW:Someone else mentioned it before: Logging in destructors would be a requirement for me, too.It would be a pity to have forbidden spaces for logging. I very much like the fact that use of printk() is so much ubiquitous.
Aug 27 2014
On Tuesday, 26 August 2014 at 18:23:31 UTC, Dicebot wrote:I will compare changelist against list of requirements from voters this weekend and if all seems to be addressed will start a new round of review/voting.sounds good! just to note, I will be mostly offline for a good week starting friday.
Aug 26 2014
On Tuesday, 26 August 2014 at 21:04:28 UTC, Robert burner Schadek wrote:On Tuesday, 26 August 2014 at 18:23:31 UTC, Dicebot wrote:Ok, going through the list of "No" voters. ==================================== Jakob Ovrum ==================================== "The *API* must support minimal dynamic memory allocation for the normal execution path. However, theoretical *implementation* changes that reduce memory allocation are not a deal-breaker." This seems to be addressed but though it is desired to verify it via nogc unittest block which uses stub no-op logger (to verify that nothing in between allocates). One place were GC allocations is unavoidable is core.d:1628 - it will always create FileLogger first and allow assigning custom one later. Is there any way to circumvent it? "API must specify a strong stance on threading, whatever the form it takes" Does not seem to be addressed at all. At least I see no mentions of it in core.d documentation and logger instance itself is plain __gshared thing. $ grep -R -n "shared" std/experimental/logger/ std/experimental/logger/core.d:1625: static __gshared Logger logger; std/experimental/logger/core.d:1635: static __gshared LogLevel ll = LogLevel.all; Does not seem enough for sure. "This one might seem unnecessarily strict, but I think the fact that Logger is a class and not an interface smells of poor design. I might still be convinced that having it as a class is justified, but my current stance is that it must be an interface." Neither does seem to be addressed nor I can find any comment on why it is not going to be addressed. ==================================== Andrei Alexandrescu ==================================== "Minimal logging level must be selected statically in addition to the current dynamic selection. Static settings preclude dynamic settings. This is not negotiable." Seems to be addressed. "All logging code must be rigorously eliminated if below the static logging level. More precisely, there must be a front-end optimization that eliminates all code dedicated to a "lazy" variable that's not used by a generic function. This would be a fantastic redeeming of the "lazy" keyword, which has been of marginal utility until now. The challenge here is cooperating with someone on the compiler team to make sure that front-end improvement gets implemented, and writing unit tests that make sure there's no regression later. This is not negotiable." Seems to be addressed. "The suffix notations must be replaced with overloads. The only acceptable suffix is "f" for formatting. Everything else must be achieved via overloads with the help of template constraints. Robert's answer http://goo.gl/FehDVh suggests he didn't consider using template constraints. We can't let that slip become a feature of the library for millenia to come." Seems to be addressed. "Replace defaultLogger with theLog. "Logger" is a word, but one that means "lumberjack" so it doesn't have the appropriate semantics. The use is generally acceptable as a nice play on words and as a disambiguator between the verb "to log" and the noun "log". When we actually want to talk about the current log in an application, we should, however, call it "the log". This is negotiable." Addressed with a name of "stdlog". "I'm still hoping for RefCounted as the storage for the class backend. I realize users can do their own management but log objects are unlikely to contain cycles and other liabilities for reference counting, and at some point if we want to use reference counting where appropriate we got to start somewhere with a few solid precedents. This is negotiable, but I plan to fight for it." Can't see any traces of RefCounted in sources though I may have missed change of mind in PR discussion (sorry it is too huge to pay regular attention) ==================================== Casey ==================================== "However, I wanted to address the suffix notation as I suggested it. What I was going for was consistency with the write/writef method signatures to keep things consistent. I felt it would be good to make the two similar since they do similar things." Obsolete with overload-based resolution ==================================== Francesco Cattoglio ==================================== "As far as I undestood, there's no way right now to do logging without using the GC. And that means it is currently impossible to log inside destructor calls. That is a blocker in my book." First part partially addressed - missing nogc nothrow logger implementation out of the box. Considering this request does not go very well with current language implementation it may be ignored for now but official stance about it must be clearly documented. ==================================== Byron Heads ==================================== "We need to hammer out how this will work inside libraries. If my app is using multiple libraries I need to know I have full control of how they log and where (), and if I write libraries I need to include logging that will not affect performance or added dependencies. I like the idea of a standard interface for D logging. Other logging implementations should be able to plug into the interface without having to inherit from std.log.Logger (single inheritance issue). I would like to see conditional logging as part of the interface, or in the documentation show how we can achieve that with stdlib in a clean and simple way." Addressed. "Logger should include a shared Logger, or include it in the interface for outside libraries to handle the implementation. There will be libraries that thread internally and will need to support shared logging." Is not addressed.I will compare changelist against list of requirements from voters this weekend and if all seems to be addressed will start a new round of review/voting.sounds good! just to note, I will be mostly offline for a good week starting friday.
Aug 29 2014
============================== David Nadlinger ============================== "I agree. For this reason, I also vote for "no" (1 as well as 2), as the current conditional logging support doubles the size of the API for shaving a grand total of 3 characters off the invocation in a rather infrequent use case." Addressed. "Wow, upon further code review I discovered that Logger actually overrides opCmp/opEquals to be based on the name (?!). This leads to the following gem: < .. >" Fixed. ============================== Martin Nowak ============================== "Get rid of the 8 different suffixes. I only see the need for log and logf, why is the rest needed?" Addressed. "Support duck-typing for the log functions. Logger should be a concept and log functions should be free-standing UFCS functions that take any `isLogger!T`. To support a global `defaultLog` variable, you could add a Logger interface and a loggerObject shim. See http://dlang.org/phobos/std_range.html#inputRangeObject for this a pattern." Neither seem to be addressed nor countered.
Aug 29 2014
I have likely missed several points but overall it seem pretty clear to me that all requests / concerns have not been addressed and this proposal is not yet ready for another round of review. Also x-post from GitHub PR of my personal nitpick: "... have noticed that all logging functions have file/line/function data as template parameters. This will create insane symbol bloat. While I can understand desire to use some nicer variadic argument API providing at least one log function that it simplistic but moves all compile-time data to run-time default argument is absolutely necessary for me to consider this viable."
Aug 29 2014
On 8/30/14, 5:18 AM, Dicebot wrote:I have likely missed several points but overall it seem pretty clear to me that all requests / concerns have not been addressed and this proposal is not yet ready for another round of review.How do the remaining issues break down into QoI that can be deferred to a future release? -- Andrei
Aug 30 2014
On Saturday, 30 August 2014 at 09:54:36 UTC, Andrei Alexandrescu wrote:On 8/30/14, 5:18 AM, Dicebot wrote:What is QoI? I am not familiar with this abbreviationI have likely missed several points but overall it seem pretty clear to me that all requests / concerns have not been addressed and this proposal is not yet ready for another round of review.How do the remaining issues break down into QoI that can be deferred to a future release? -- Andrei
Aug 30 2014
On Sat, Aug 30, 2014 at 01:08:05PM +0000, Dicebot via Digitalmars-d wrote:On Saturday, 30 August 2014 at 09:54:36 UTC, Andrei Alexandrescu wrote:Quality of Implementation. T -- The peace of mind---from knowing that viruses which exploit Microsoft system vulnerabilities cannot touch Linux---is priceless. -- Frustrated system administrator.On 8/30/14, 5:18 AM, Dicebot wrote:What is QoI? I am not familiar with this abbreviationI have likely missed several points but overall it seem pretty clear to me that all requests / concerns have not been addressed and this proposal is not yet ready for another round of review.How do the remaining issues break down into QoI that can be deferred to a future release? -- Andrei
Aug 30 2014
On Saturday, 30 August 2014 at 13:35:57 UTC, H. S. Teoh via Digitalmars-d wrote:And how can one break issues into quality of implementation? :O I have literally no idea what Andrei means.Quality of Implementation.How do the remaining issues break down into QoI that can be deferred to a future release? -- AndreiWhat is QoI? I am not familiar with this abbreviation
Aug 30 2014
On Sat, Aug 30, 2014 at 01:37:15PM +0000, Dicebot via Digitalmars-d wrote:On Saturday, 30 August 2014 at 13:35:57 UTC, H. S. Teoh via Digitalmars-d wrote:I'm guessing he means, break them down into must-solve-before-merge issues and stuff-to-be-fixed-later issues. T -- Acid falls with the rain; with love comes the pain.And how can one break issues into quality of implementation? :O I have literally no idea what Andrei means.Quality of Implementation.How do the remaining issues break down into QoI that can be >deferred to a future release? -- AndreiWhat is QoI? I am not familiar with this abbreviation
Aug 30 2014
On 8/30/14, 4:42 PM, H. S. Teoh via Digitalmars-d wrote:On Sat, Aug 30, 2014 at 01:37:15PM +0000, Dicebot via Digitalmars-d wrote:Correct. (I'm on vacation with scarce online access.) -- AndreiOn Saturday, 30 August 2014 at 13:35:57 UTC, H. S. Teoh via Digitalmars-d wrote:I'm guessing he means, break them down into must-solve-before-merge issues and stuff-to-be-fixed-later issues.And how can one break issues into quality of implementation? :O I have literally no idea what Andrei means.Quality of Implementation.How do the remaining issues break down into QoI that can be >deferred to a future release? -- AndreiWhat is QoI? I am not familiar with this abbreviation
Aug 30 2014
On Saturday, 30 August 2014 at 20:53:58 UTC, Andrei Alexandrescu wrote:Correct. (I'm on vacation with scarce online access.) -- AndreiWith API stability in mind defining official stance on multi-threading in most important part. Rest can be added with small to none breaking changes.
Aug 30 2014
I've got some questions: How does logging interact with pure? You need to be able to log in pure functions. Does the logger implementation flush() in the case of a crash? (Does it trap all crashes in a way that ensures that logging buffers are written to disk?) Is logf() needed? Can't you somehow detect that the string is an immutable string literal with string formatting characters?
Aug 30 2014
Am Sun, 31 Aug 2014 01:09:32 +0000 schrieb "Ola Fosheim Gr=C3=B8stad" <ola.fosheim.grostad+dlang gmail.com>:I've got some questions: =20 How does logging interact with pure? You need to be able to log=20 in pure functions.How do you come to that conclusion? Purity is a synonym for _not_ having side effects. That said - as usual - "debug" statements allow you to punch a hole into purity.[=E2=80=A6] =20 Is logf() needed? Can't you somehow detect that the string is an=20 immutable string literal with string formatting characters?1) The first argument does not need to be a literal. 2) Checking the first argument for formatting chars slows the system down. 3) If you want to log a regular string, e.g. an incoming HTTP request or something that contains formatting symbols, log() would throw an exception about a missing second argument. This in turn could become a DOS vulnerability. Other than that, you could create an additional log function that only accepts compile-time known formatting strings as a CT argument and verifies the runtime argument types at the same time. --=20 Marco
Aug 30 2014
On Sunday, 31 August 2014 at 06:11:56 UTC, Marco Leise wrote:Am Sun, 31 Aug 2014 01:09:32 +0000 schrieb "Ola Fosheim Grøstad" <ola.fosheim.grostad+dlang gmail.com>:1. ~90% of all functions are weakly pure, if you cannot log execution in those functions then logging becomes a liability. 2. If you define logging in a weakly pure function as tracing of execution rather than logging of state, then you can allow memoization too. 3. You don't normally read back the log in the same execution, state is thus not preserved through logging within a single execution. It has traits which makes it less problematic than general side effects that change regular global variables.How does logging interact with pure? You need to be able to log in pure functions.How do you come to that conclusion? Purity is a synonym for _not_ having side effects. That said - as usual - "debug" statements allow you to punch a hole into purity.
Aug 31 2014
Am Sun, 31 Aug 2014 08:52:58 +0000 schrieb "Ola Fosheim Gr=C3=B8stad" <ola.fosheim.grostad+dlang gmail.com>:On Sunday, 31 August 2014 at 06:11:56 UTC, Marco Leise wrote:Ok, here is the current state: Logging is not a first-class language feature with special semantics. Drop your "pure" keywords on those 90% of functions or only log in "debug". =20Am Sun, 31 Aug 2014 01:09:32 +0000 schrieb "Ola Fosheim Gr=C3=B8stad" <ola.fosheim.grostad+dlang gmail.com>:=20=20 1. ~90% of all functions are weakly pure, if you cannot log=20 execution in those functions then logging becomes a liability. 2. If you define logging in a weakly pure function as tracing of=20 execution rather than logging of state, then you can allow=20 memoization too.How does logging interact with pure? You need to be able to=20 log in pure functions.How do you come to that conclusion? Purity is a synonym for _not_ having side effects. That said - as usual - "debug" statements allow you to punch a hole into purity.3. You don't normally read back the log in the same execution,=20 state is thus not preserved through logging within a single=20 execution. It has traits which makes it less problematic than=20 general side effects that change regular global variables.I still don't see it fly even theoretically. The "stdlog" will be an interface with an arbitrary implementation behind it. A file logger will eventually hit a "disk full" state and throw an exception. Since "pure" implies that a function call can be elided such a change of execution path cannot work. It is much like discussing the strictness of transitive const. If you need to cache values of initialize on first access, you just have to drop const. --=20 Marco
Aug 31 2014
On Sunday, 31 August 2014 at 09:34:51 UTC, Marco Leise wrote:Am Sun, 31 Aug 2014 08:52:58 +0000 schrieb "Ola Fosheim Grøstad" <ola.fosheim.grostad+dlang gmail.com>:On Sunday, 31 August 2014 at 06:11:56 UTC, Marco Leise wrote:Am Sun, 31 Aug 2014 01:09:32 +0000 schrieb "Ola Fosheim Grøstad" <ola.fosheim.grostad+dlang gmail.com>:I still don't see it fly even theoretically. The "stdlog" will be an interface with an arbitrary implementation behind it. A file logger will eventually hit a "disk full" state and throw an exception.Why would that be the sole outcome? There are several strategies to cope with that, maybe through a special logger. For example: - start writing over the old logs transparently (because, usually, the most important logs are the most recent ones) - simply fake logging, but not logging anything more (keeping all history and simply discard anything that comes after the disk is full) These could be solved easily, by catching the exception and either processing it (the first strategy), either by ignoring it (the second strategy). But it matters to have the functionality by default.
Aug 31 2014
On Sunday, 31 August 2014 at 09:34:51 UTC, Marco Leise wrote:Ok, here is the current state: Logging is not a first-class language feature with special semantics. Drop your "pure" keywords on those 90% of functions or only log in "debug".Then maybe the language lacks features that allow you to escape purity in a safe manner. But maybe you should only allow "trace()" and not "log()" in pure functions. Tracing execution and logging state.I still don't see it fly even theoretically. The "stdlog" will be an interface with an arbitrary implementation behind it.An interface can require specific properties of the implementation.file logger will eventually hit a "disk full" state and throw an exception. Since "pure" implies that a function call can be elided such a change of execution path cannot work.Not sure what you mean by this. The logger I am most interested in writes to a circular buffer and uploads the log to a database on a crash so that the source of the crash can be identified. I am only interested in in logging execution, not preserved state without execution. It is not uncommon to have loggers that writes to a fixed size preallocated area that behaves like a circular buffer (e.g. retain at most 1GB and <3 months old logging-data)
Aug 31 2014
On Sunday, 31 August 2014 at 09:56:29 UTC, Ola Fosheim Grøstad wrote:The logger I am most interested in writes to a circular buffer and uploads the log to a database on a crash so that the source of the crash can be identified. I am only interested in in logging execution, not preserved state without execution.Does this logger already exist, could I take a look at it? If not, if someone writes an appender for writing to the database, you could accomplish this goal with log4d using a buffer appender that triggers on fatal.
Aug 31 2014
On Monday, 1 September 2014 at 04:32:42 UTC, Kevin Lamonte wrote:Does this logger already exist, could I take a look at it?Not in D AFAIK, circular in-memory logging is a common technique for fixing servers though.If not, if someone writes an appender for writing to the database, you could accomplish this goal with log4d using a buffer appender that triggers on fatal.I guess the most robust solution is to use shared memory and fork, when the child dies you soup up the log and upload it to a logging-server. I am also interested in lazy formatting, meaning you log a reference to the immutable formatting string and the parameters, but wait with the formatting until the result is needed.
Sep 01 2014
On Monday, 1 September 2014 at 10:43:34 UTC, Ola Fosheim Grøstad wrote:I guess the most robust solution is to use shared memory and fork, when the child dies you soup up the log and upload it to a logging-server.I'm used to a centralized system taking logs on a continuous basis, with "normal, I'm happy" messages coming through in a regular interval. When the application dies, it already has had its messages emitted and sucked up by the collection system, and if its heartbeat messages aren't seen then people are prompted to investigate anyway. It's on the main server (e.g. syslog or LogStash) to handle storage space issues like log rotation.I am also interested in lazy formatting, meaning you log a reference to the immutable formatting string and the parameters, but wait with the formatting until the result is needed.log4d does this, it saves the Logger+LogEntry references and only applies PatternLayouts at the end, BUT it does so with the risk that additional fields specified in the conversionPattern might be wrong since they were not generated/evaluated in the context of the original log call. Thread ID (%t) is the main culprit (since it is not in LogEntry, PatternLayout has to get it), but also time between log calls and time since application startup (%r/%R). But it sounds like you want std.logger to not apply formatting even in its infof/errorf/etc functions. That might be a problem for things like the number of rows in a result set, the current time, or the remote system hostname. For example, by the time the logging infrastructure evaluates the number of rows, the result set is long gone and could throw an exception. I would argue that this kind of lazy evaluation would be fine if it was not enabled by default.
Sep 01 2014
On Tuesday, 2 September 2014 at 06:24:45 UTC, Kevin Lamonte wrote:I'm used to a centralized system taking logs on a continuous basis, with "normal, I'm happy" messages coming through in a regular interval. When the application dies, it already has had its messages emitted and sucked up by the collection system, and if its heartbeat messages aren't seen then people are prompted to investigate anyway. It's on the main server (e.g. syslog or LogStash) to handle storage space issues like log rotation.Yes, I think we are discussing many different things at the same time here and it would be a good idea to sort out the different use cases since that affects functionality. I have not thought about heartbeats/keep-alive etc as logging, but it is reasonable to view them as such. I see a difference between signalling state, tracing execution and logging state. I guess one roughly can say that: - signalling is for coordination of subsystems - logging state is for tracking effects on the database - tracing is for detecting logic failure after a crash ?log4d does this, it saves the Logger+LogEntry references and only applies PatternLayouts at the end, BUT it does so with the risk that additional fields specified in the conversionPattern might be wrong since they were not generated/evaluated in the context of the original log call. Thread ID (%t) is the main culprit (since it is not in LogEntry, PatternLayout has to get it), but also time between log calls and time since application startup (%r/%R).Sounds interesting. I'll have a look at log4d later. But it is not fully typesafe then? The way I see it you should log a tuple of values and a reference to a type-safe formatting expression, but only apply the formatting expression when you need to so you don't burden the performance thread with unnecessary work.But it sounds like you want std.logger to not apply formatting even in its infof/errorf/etc functions. That might be a problem for things like the number of rows in a result set, the current time, or the remote system hostname. For example, by the time the logging infrastructure evaluates the number of rows, the result set is long gone and could throw an exception.I think you should log the values as a tuple, but not do the string-conversion, but it is more important for tracing execution than for logging. I guess formatting high level info/error is acceptable, but for tracing I am only interested in very terse value/type info along with an indicator of context. Performance and trouble-free type safe logging is much more important than "nice formatting" IMO. Traced execution will primarily be used for log analysis after a crash. You can use this on game clients, game servers, web servers etc… E.g.: log configuration + trace last 50000 events -> crash -> compress and upload for analysis.
Sep 02 2014
On Tuesday, 2 September 2014 at 10:14:27 UTC, Ola Fosheim Grøstad wrote:On Tuesday, 2 September 2014 at 06:24:45 UTC, Kevin Lamonte wrote:I see a difference between signalling state, tracing execution and logging state. I guess one roughly can say that: - signalling is for coordination of subsystems - logging state is for tracking effects on the database - tracing is for detecting logic failure after a crashI've written my own ideas about logging vs tracing over at https://github.com/klamonte/log4d/docs/philosophy.md . In a nutshell, "logging" means the engineered messages targeting non-developers that are part of the application deliverable and follow the narrative flow, while tracing is the automated messages targeting the developers that follow the structural flow. std.logger provides an acceptable interface for logging and an absolute minimal interface to tracing, with just the single LogLevel.trace and trace/tracef functions. Most other systems provide at least two (debug+trace) or three (fine/finer/finest) levels between INFO and everything, and some provide log.entering()/log.exiting() functions that could provide for what you are describing.Sounds interesting. I'll have a look at log4d later. But it is not fully typesafe then? The way I see it you should log a tuple of values and a reference to a type-safe formatting expression, but only apply the formatting expression when you need to so you don't burden the performance thread with unnecessary work.Well, sort of. It's not CTFE-like typesafe where the compiler catches it, but it also isn't possible (AFAIK) to get it wrong either. PatternLayout's "format" specifiers don't perform conversions on client-controlled input, they are straight substitutions of the LogEntry fields (+ some extras) into the final emitted string. It sounds like what you would like is a trace function that doesn't feature a format string at all, but formatting would instead be applied at I/O time by a Logger subclass. How about this? 1. Add a "fnArgs" field of type Object [] to LogEntry 2, Add something like the following: void traceFn(int line = __LINE__, string file = __FILE__, string funcName = __FUNCTION__, string prettyFuncName = __PRETTY_FUNCTION__, string moduleName = __MODULE__)(lazy Object [] fnArgs) trusted { static if (isLoggingActive!LogLevel.trace) { if (isLoggingEnabled(LogLevel.trace) && ll >= stdlog.logLevel && stdlog.logLevel >= globalLogLevel && globalLogLevel != LogLevel.off && stdlog.logLevel != LogLevel.off) { auto entry = LogEntry(file, line, funcName, prettyFuncName, moduleName, LogLevel.trace, thisTid, Clock.currTime, null, this, fnArgs); this.writeLogMsg(entry); } } } This could also be split into traceFnEnter, traceFnExitSuccess, and traceFnExitFailure with LogEntry.args set to indicate which one (">", "<", "!<" for example) and a mixin provided so that client code could get it all in a one-liner. If this would meet your needs, I wouldn't mind it myself. Save log.trace() for generic messages the developer want to see between the traceFnEnter/traceFnExitX messages.
Sep 03 2014
On Wednesday, 3 September 2014 at 11:39:59 UTC, Kevin Lamonte wrote:I've written my own ideas about logging vs tracing over at https://github.com/klamonte/log4d/docs/philosophy.mdNice writeup! It is kind of interesting that there are so many different takes on a mundane task such as logging, monitoring, debug-tracing etc. Reminds me of reflections on how many types of NULL you need to cover all the different semantics that NULL can express (was it 5 or 6?).It sounds like what you would like is a trace function that doesn't feature a format string at all, but formatting would instead be applied at I/O time by a Logger subclass.Yes, either that or no formatting at all. If all formatting strings are literals and resolve at compile time then you can extract them from the source and create a big compile time map that convert them into numeric values at compile time and convert the types into numeric values as well. If the API supports full compile time reflection that should be a possibility. High performance logging should just be a series of MOV instructions or SSE equivalents that completes in ~8-40 cycles for a circular buffer with 2^N size. With increasing availability of memory on cloud servers this becomes more and more attractive IMO (you can log a lot in 50MB) It important is that you exploit the fact that the values are already in registers because you usually log values that have recently been computed and that you spend a minimal amount of execution time on registering them, perhaps even writing directly to full memory cache lines to avoid cache pollution (using special SSE commands). If you accept slightly out of sync logging then you can have thread local buffers and on x86 use the command RDTSC which gives you a (good enough) timer value so you can merge the buffers from threads later. It takes roughly 20-30 cycles which I presume is better than CAS instructions, or you can just write directly to a global counter without CAS and accept that it jitters? I personally don't care about enter/exit so much. I care about: 1. tracking the state of the system configuration at the point of failure 2. the paths of execution before the incident 3. the events that led up to it (in order to reproduce the failure).This could also be split into traceFnEnter, traceFnExitSuccess, and traceFnExitFailure with LogEntry.args set to indicate which one (">", "<", "!<" for example) and a mixin provided so that client code could get it all in a one-liner.Sounds like a candidate for an attribute, just prefix a function or function call with trace(level)?
Sep 03 2014
On Wednesday, 3 September 2014 at 13:13:31 UTC, Ola Fosheim Grøstad wrote:On Wednesday, 3 September 2014 at 11:39:59 UTC, Kevin Lamonte wrote:I've got a feature request in for just that: https://issues.dlang.org/show_bug.cgi?id=13406 While thinking about it I realize that it's actually very easy to generalize trace into the equivalent of Common Lisp :before, :after, and :around methods: scope(&scopeFn) . (It would work even better if scope(success) and scope(failure) exposed what they are returning/throwing.) In the meantime Log4D has a (barely tested) mixin.This could also be split into traceFnEnter, traceFnExitSuccess, and traceFnExitFailure with LogEntry.args set to indicate which one (">", "<", "!<" for example) and a mixin provided so that client code could get it all in a one-liner.Sounds like a candidate for an attribute, just prefix a function or function call with trace(level)?
Sep 03 2014
On Wednesday, 3 September 2014 at 22:34:30 UTC, Kevin Lamonte wrote:I've got a feature request in for just that: https://issues.dlang.org/show_bug.cgi?id=13406Interesting! I am not 100% convinced that scope(failure/success) is the way to go since it will cause potentially a lot of extra work when unwinding the stack in case of an exception? Or maybe the stack unwinder could to the tracing directly without using the scope construct. Another option would be to only trace the landing-pad ("catch statement") for exceptions, so you would get something like "exception X caught in functionname()", but not sure how to do it without loosing information. You might need a counter for each enter/exit or something like that and let the stack-unwinder count down.
Sep 03 2014
On Thursday, 4 September 2014 at 04:53:36 UTC, Ola Fosheim Grøstad wrote:You might need a counter for each enter/exit or something like that and let the stack-unwinder count down.I meant: you might need to "increment a stack specific counter", but that does not sound practical. I guess it is better to have a more complex stack unwinder. Co-routines create some problems here. You probably need to trace that they yield.
Sep 03 2014
On Wednesday, 3 September 2014 at 22:34:30 UTC, Kevin Lamonte wrote:This can already be implemented in a library if "mixin of an implementation" idiom is used. I think it fits D style better (having attributes modify actual code flow is unprecedented)Sounds like a candidate for an attribute, just prefix a function or function call with trace(level)?I've got a feature request in for just that: https://issues.dlang.org/show_bug.cgi?id=13406 While thinking about it I realize that it's actually very easy to generalize trace into the equivalent of Common Lisp :before, :after, and :around methods: scope(&scopeFn) . (It would work even better if scope(success) and scope(failure) exposed what they are returning/throwing.) In the meantime Log4D has a (barely tested) mixin.
Sep 05 2014
On Wednesday, 3 September 2014 at 13:13:31 UTC, Ola Fosheim Grøstad wrote:If you accept slightly out of sync logging then you can have thread local buffers and on x86 use the command RDTSC which gives you a (good enough) timer value so you can merge the buffers from threads later. It takes roughly 20-30 cycles which I presume is better than CAS instructions, or you can just write directly to a global counter without CAS and accept that it jitters?Since we are talking about performance, I did some tests and found to my surprise that ~95% of the time consumed in a log call is Clock.currTime's call to clock_gettime(). I submitted a report for it (https://issues.dlang.org/show_bug.cgi?id=13433), but it also brings up how to expose it in the std.logger API. The API automatically grabs thisTid and Clock.currTime during construction of the LogEntry (plus it should also grab Thread.getThis and Fiber.getThis). Should this behavior be modifiable by clients, by subclasses, or neither? If so, how?
Sep 06 2014
On Saturday, 6 September 2014 at 19:41:54 UTC, Kevin Lamonte wrote:The API automatically grabs thisTid and Clock.currTime during construction of the LogEntry (plus it should also grab Thread.getThis and Fiber.getThis). Should this behavior be modifiable by clients, by subclasses, or neither? If so, how?I think maybe we should start with creating a high performance inlined (for ldc/gdc) in-memory multi-threaded binary reference logger and then extend the interface in ways that does not make it noticeably slower using the reference logger as the baseline. (Noticeably > 100%?) When logging to an external logging service you might want the logging service do the time-keeping so you don't get merged logs from multiple servers that are out of sync. In that case collecting absolute time locally is kinda pointless (although you might want to submit serial numbers and relative time between logging events from the same server).
Sep 06 2014
On Saturday, 6 September 2014 at 19:41:54 UTC, Kevin Lamonte wrote:On Wednesday, 3 September 2014 at 13:13:31 UTC, Ola Fosheim Grøstad wrote:Since we are talking about performance, I did some tests and found to my surprise that ~95% of the time consumed in a log call is Clock.currTime's call to clock_gettime(). I submitted a report for it (https://issues.dlang.org/show_bug.cgi?id=13433), but it also brings up how to expose it in the std.logger API.that is with all likelihood a syscall, so there goes your performanceThe API automatically grabs thisTid and Clock.currTime during construction of the LogEntry (plus it should also grab Thread.getThis and Fiber.getThis). Should this behavior be modifiable by clients, by subclasses, or neither? If so, how?yes, I will move some of it into beginLogMsg
Sep 09 2014
On Sunday, 31 August 2014 at 01:09:33 UTC, Ola Fosheim Grøstad wrote:I've got some questions: How does logging interact with pure? You need to be able to log in pure functions.Weakly pure function can take logger as an argument (so I doubt it is useful in practice). Strongly pure functions can't be logged in non-debug statement pretty much by D definition of purity. This may be or may not be an issue but is definitely goes out of the scope of this Phobos proposal. If you have any specific ideas how to address it, please create a separate thread.Does the logger implementation flush() in the case of a crash? (Does it trap all crashes in a way that ensures that logging buffers are written to disk?)Current implementations use basic std.stdio facilities and those flush upon writing a newline symbol -> flush happens after each log call. More efficient buffered implementation can be provided later, this shouldn't affect the API.Is logf() needed? Can't you somehow detect that the string is an immutable string literal with string formatting characters?Unreliable, not KISS. I think it is a bad idea.
Sep 01 2014
On Monday, 1 September 2014 at 16:30:46 UTC, Dicebot wrote:purity. This may be or may not be an issue but is definitely goes out of the scope of this Phobos proposal. If you have any[…]Current implementations use basic std.stdio facilities and those flush upon writing a newline symbol -> flush happens after each log call. More efficient buffered implementation can be provided later, this shouldn't affect the API.[…]Unreliable, not KISS. I think it is a bad idea.If the standard library does not provide the following from the get go: 1. general usefulness 2. performance 3. KISS in terms of interface (not in language semantics) then people will be better off rolling their own. Creating a simple logger is not difficult, the challenge is in creating a performant, generally useful one with legible syntax and full CT type safety.
Sep 01 2014
On Monday, 1 September 2014 at 16:45:29 UTC, Ola Fosheim Grøstad wrote:If the standard library does not provide the following from the get go: 1. general usefulness 2. performance 3. KISS in terms of interface (not in language semantics) then people will be better off rolling their own. Creating a simple logger is not difficult, the challenge is in creating a performant, generally useful one with legible syntax and full CT type safety.You are totally misunderstanding goals of std.logger - people as _expected_ to roll their own Loggers. std.logger is here only to provide standard API for those to integrate with each other and few trivial common implementation as examples. Rest is dub business. And no, magic identification of format string is neither language KISS nor interface KISS.
Sep 01 2014
On Monday, 1 September 2014 at 16:52:16 UTC, Dicebot wrote:You are totally misunderstanding goals of std.logger - people as _expected_ to roll their own Loggers. std.logger is here*are expected
Sep 01 2014
On Monday, 1 September 2014 at 16:52:16 UTC, Dicebot wrote:You are totally misunderstanding goals of std.logger - people as _expected_ to roll their own Loggers. std.logger is here only to provide standard API for those to integrate with each other and few trivial common implementation as examples. Rest is dub business.Oh, I understand the intentions perfectly well, but the default should be performant, multithreaded, and cover the most common use scenario. Without a performant reference implementation that can be used for performance testing it isn't convincing. You also need to account for issues such as multi-threading, throttling etc. Meaning, you might need to have queues and a merger-thread, defer formatting etc etc.And no, magic identification of format string is neither language KISS nor interface KISS.Formatting should be typesafe and preferably configurable with custom formatters, so it should resolve at compile-time one way or the other. You don't want an exceptional path to have a runtime error triggered by a log() statement, i.e. you don't want the possibility that turning on logging can introduce bugs. That should be the most important requirement.
Sep 01 2014
On Monday, 1 September 2014 at 18:57:25 UTC, Ola Fosheim Grøstad wrote:On Monday, 1 September 2014 at 16:52:16 UTC, Dicebot wrote:+1 While its useful for the standard library to provide stubs, these mean very little without a default implementation. And the latter shall be quite generic to cover most of the use cases. Rolling one's own loggers shall be done only if the world is not enough.You are totally misunderstanding goals of std.logger - people as _expected_ to roll their own Loggers. std.logger is here only to provide standard API for those to integrate with each other and few trivial common implementation as examples. Rest is dub business.Oh, I understand the intentions perfectly well, but the default should be performant, multithreaded, and cover the most common use scenario.
Sep 01 2014
On Tuesday, 2 September 2014 at 06:53:30 UTC, eles wrote:I disagree and it was declared among goals of this module from the very beginning that it won't go that way, won't even attempt to do it. If you have some good ideas about better default implementation - make pull request after it is merged into "std.experimental". Right now it is not in the scope of the review and I will simply ignore all comments that are related purely to implementation. However, if there any API issues that will likely block the implementation you want - those are very important to hear about.Oh, I understand the intentions perfectly well, but the default should be performant, multithreaded, and cover the most common use scenario.+1 While its useful for the standard library to provide stubs, these mean very little without a default implementation. And the latter shall be quite generic to cover most of the use cases. Rolling one's own loggers shall be done only if the world is not enough.
Sep 02 2014
On Tuesday, 2 September 2014 at 07:10:29 UTC, Dicebot wrote:into "std.experimental". Right now it is not in the scope of the review and I will simply ignore all comments that are related purely to implementation.Configuration of logging is part of the API. Conversion of objects to log info affects the API. The API affects performance. You need to design the API with a reference model in mind. Without it the API has no value. That's why you need a reference implementation in order to evaluate the API design.However, if there any API issues that will likely block the implementation you want - those are very important to hearI am concerned about performance, formatting and type safety. You need to: 1. define the use cases you want to cover 2. list the requirements 3. define a model Only then does it make sense to define the API. If D is to have the upper hand as a system level language then the logging must be performant. For performant logging you might not want to do string-formatting at all in the engine you are monitoring.
Sep 02 2014
On Tuesday, 2 September 2014 at 10:25:03 UTC, Ola Fosheim Grøstad wrote:Sorry but it doesn't work that way. If you are concerned about those cases it is you who must do necessary research and provided specific list of requirements / changes. No one else is going to do it. While your raise important concerns it doesn't have any practical application right now and I can't use it in any way as part of review process. We need details (see the responses of other voters). Pure theoretical speculations won't help.However, if there any API issues that will likely block the implementation you want - those are very important to hearI am concerned about performance, formatting and type safety. You need to: 1. define the use cases you want to cover 2. list the requirements 3. define a model Only then does it make sense to define the API. If D is to have the upper hand as a system level language then the logging must be performant. For performant logging you might not want to do string-formatting at all in the engine you are monitoring.
Sep 02 2014
On Tuesday, 2 September 2014 at 13:08:02 UTC, Dicebot wrote:While your raise important concerns it doesn't have any practical application right now and I can't use it in any way as part of review process. We need details (see the responses of other voters). Pure theoretical speculations won't help.Uhm, it isn't theoretical. A low performance string based stdio-logger is not useful in a high performance server where you have short spikes with idle time between the spikes. A coarse grained logger logs state on the application level and I don't need library support for that since it only happens in a handful of locations that I control myself. A fine grained logger logs state on the framework/library level and I don't want to use a logger that spends time on turning ints into strings when it is supposed to be handling requests and sits idle a few milliseconds later. The phobos design lacks a performance oriented focus and si too scripty for a system level langauge. You need benchmarking from the get go. Performance does not happen later as a QoI issue because performance depends on the model the API implies. Fine grained logging must be performant.
Sep 02 2014
On Tuesday, 2 September 2014 at 13:58:24 UTC, Ola Fosheim Grøstad wrote:On Tuesday, 2 September 2014 at 13:08:02 UTC, Dicebot wrote:This is exactly what I call theoretical speculations. Please provide specific list like this: 1) some method signature needs to be changed 2) design decision that makes GC allocation unavoidable for specific use case 3) example logger implementation that doesn't fit into existing API (show how) If you are going to speak more about abstract performance I am going to simply ignore any of your further posts on topic. Sorry but there is no other way.While your raise important concerns it doesn't have any practical application right now and I can't use it in any way as part of review process. We need details (see the responses of other voters). Pure theoretical speculations won't help.Uhm, it isn't theoretical. A low performance string based stdio-logger is not useful in a high performance server where you have short spikes with idle time between the spikes. A coarse grained logger logs state on the application level and I don't need library support for that since it only happens in a handful of locations that I control myself. A fine grained logger logs state on the framework/library level and I don't want to use a logger that spends time on turning ints into strings when it is supposed to be handling requests and sits idle a few milliseconds later. The phobos design lacks a performance oriented focus and si too scripty for a system level langauge. You need benchmarking from the get go. Performance does not happen later as a QoI issue because performance depends on the model the API implies. Fine grained logging must be performant.
Sep 02 2014
On Tuesday, 2 September 2014 at 14:53:17 UTC, Dicebot wrote:If you are going to speak more about abstract performance I am going to simply ignore any of your further posts on topic.I am not abstract. These are very concrete requirements: 1. You have to be able to determine types and formatting at compile time otherwise you cannot do binary logging. 2. You have to be able to determine types and formatting at compile time otherwise you cannot minimize the probability of introducing run-time errors by turning on full logging. This is very important use scenarios: * Performant fine grained logging (as close to zero overhead as you get) in libraries and frameworks is essential for fixing cloud-based servers where you typically cannot use regular strategies. I don't control frameworks, so it is important that they use standard lib logging. * Performant fine grained logging (as close to zero overhead as you get) in client side frameworks is essential for fixing online game clients that runs on heterogenous hardware since you don't get to run a debugger on all configurations. I don't know enough about what the limitations for advanced compile time reflection is, but it has been claimed in this thread that the current design does not make it possible to establish this at compile time. Then I have to conclude that the current design cannot be safe enough or performant enough to be useful in libraries and frameworks and give D an advantage in the server-market... Risks: 1. If D libraries and frameworks starts using and under-performing logger because it is the official D logger library, then you cannot ship products with fine grained logging based on these framworks. This is a lost opportunity. 2. If phobos includes under-performing libraries then you risk having a new split and have two standard libraries and/or two incompatible logging frameworks.
Sep 02 2014
On Tuesday, 2 September 2014 at 15:10:35 UTC, Ola Fosheim Grøstad wrote:On Tuesday, 2 September 2014 at 14:53:17 UTC, Dicebot wrote:Ok, this is much more specific. With a similar concerns in mind I have proposed to add a `log` overload that doesn't have variadic arguments and takes a single pre-formatted string (with file/line/module as default run-time arguments). With a custom formatting function (compile-time or run-time at users choice) it should fit these requirements. Does that sounds feasible to you?If you are going to speak more about abstract performance I am going to simply ignore any of your further posts on topic.I am not abstract. These are very concrete requirements: 1. You have to be able to determine types and formatting at compile time otherwise you cannot do binary logging. 2. You have to be able to determine types and formatting at compile time otherwise you cannot minimize the probability of introducing run-time errors by turning on full logging.
Sep 05 2014
On Friday, 5 September 2014 at 18:24:01 UTC, Dicebot wrote:Ok, this is much more specific. With a similar concerns in mind I have proposed to add a `log` overload that doesn't have variadic arguments and takes a single pre-formatted string (with file/line/module as default run-time arguments). With a custom formatting function (compile-time or run-time at users choice) it should fit these requirements. Does that sounds feasible to you?P.S. Reason why compile-time format checking can't be added to base API is rather simple - it needs to be at least somewhat similar to one of writefln
Sep 05 2014
On Friday, 5 September 2014 at 18:27:12 UTC, Dicebot wrote:P.S. Reason why compile-time format checking can't be added to base API is rather simple - it needs to be at least somewhat similar to one of writeflnHm. My experience with Python for server use tells me that the problem with dynamic languages isn't the primarily the main execution paths, but the exceptional ones. Having to update a server because a request erroneously fails due to a logging statement (or typos in asserts or any other kind of debugging statement) is annoying. Upon further reflection I think it is important to require logging to be a fail-safe transparent operation (conceptually close to an annotation). I don't think monitoring statements should be able to cause runtime errors at all.
Sep 05 2014
On Tuesday, 2 September 2014 at 14:53:17 UTC, Dicebot wrote:This is exactly what I call theoretical speculations. Please provide specific list like this: 1) some method signature needs to be changedI propose the following API changes (+ changes on default implementation): protected LogEntry beginLogMsg(string file, int line, string funcName, string prettyFuncName, string moduleName, LogLevel logLevel, Tid threadId, SysTime timestamp, Logger logger) trusted { static if (isLoggingActive()) { return LogEntry(file, line, funcName, prettyFuncName, moduleName, logLevel, threadId, timestamp, null, logger); } } /** Logs a part of the log message. */ protected void logMsgPart(MsgRange msgAppender, const(char)[] msg) { static if (isLoggingActive()) { msgAppender.put(msg); } } /** Signals that the message has been written and no more calls to $(D logMsgPart) follow. */ protected void finishLogMsg(ref LogEntry entry, MsgRange msgAppender) { static if (isLoggingActive()) { entry.msg = msgAppender.data; this.writeLogMsg(entry); } } ...with the corresponding changes to logImpl/logImplf to create msgAppender as a local function variable, and the elimination of header and msgAppender as Logger class variables. The benefit to this change is that Logger (including stdlog) becomes thread-safe, as well as any subclass of Logger that only implements writeLogMsg().
Sep 02 2014
On Wednesday, 3 September 2014 at 03:05:42 UTC, Kevin Lamonte wrote:On Tuesday, 2 September 2014 at 14:53:17 UTC, Dicebot wrote:The only problem with that change is that it will always require a buffer. FileLogger currently doesn't require a buffer and is already thread-safe. stdlog will not be thread-safe by default by this change only syncing the writeLogMsg function will.This is exactly what I call theoretical speculations. Please provide specific list like this: 1) some method signature needs to be changedI propose the following API changes (+ changes on default implementation): protected LogEntry beginLogMsg(string file, int line, string funcName, string prettyFuncName, string moduleName, LogLevel logLevel, Tid threadId, SysTime timestamp, Logger logger) trusted { static if (isLoggingActive()) { return LogEntry(file, line, funcName, prettyFuncName, moduleName, logLevel, threadId, timestamp, null, logger); } } /** Logs a part of the log message. */ protected void logMsgPart(MsgRange msgAppender, const(char)[] msg) { static if (isLoggingActive()) { msgAppender.put(msg); } } /** Signals that the message has been written and no more calls to $(D logMsgPart) follow. */ protected void finishLogMsg(ref LogEntry entry, MsgRange msgAppender) { static if (isLoggingActive()) { entry.msg = msgAppender.data; this.writeLogMsg(entry); } } ...with the corresponding changes to logImpl/logImplf to create msgAppender as a local function variable, and the elimination of header and msgAppender as Logger class variables. The benefit to this change is that Logger (including stdlog) becomes thread-safe, as well as any subclass of Logger that only implements writeLogMsg().
Sep 08 2014
Another API change: LogEntry must have a Thread reference, either in addition to or in replacement of the Tid reference it has currently.
Sep 03 2014
On Saturday, 30 August 2014 at 13:37:17 UTC, Dicebot wrote:On Saturday, 30 August 2014 at 13:35:57 UTC, H. S. Teoh via Digitalmars-d wrote:Implementation issues can be fixed later as long as the API allows for it, so we should focus on the latter.And how can one break issues into quality of implementation? :O I have literally no idea what Andrei means.Quality of Implementation.How do the remaining issues break down into QoI that can be deferred to a future release? -- AndreiWhat is QoI? I am not familiar with this abbreviation
Aug 30 2014
On Saturday, 30 August 2014 at 02:18:30 UTC, Dicebot wrote:I have likely missed several points but overall it seem pretty clear to me that all requests / concerns have not been addressed and this proposal is not yet ready for another round of review.I made the stdlog creating thread-safe and on stack. I think that was the last point that was mentioned.Also x-post from GitHub PR of my personal nitpick: "... have noticed that all logging functions have file/line/function data as template parameters. This will create insane symbol bloat. While I can understand desire to use some nicer variadic argument API providing at least one log function that it simplistic but moves all compile-time data to run-time default argument is absolutely necessary for me to consider this viable."I do not consider that a problem. The benefit is much higher than the cost of the bigger binary. This has already been a long conversation on some previous thread.
Sep 09 2014
On Tuesday, 9 September 2014 at 19:38:16 UTC, Robert burner Schadek wrote:This unfortunately makes it almost unusable in absence of --gc-sections supporting compiler for lower level domains. Probably I am missing some data though, can you link the discussion thread? This PR dicussion is so long now that it hangs my browser when uncollapsing threads :(Also x-post from GitHub PR of my personal nitpick: "... have noticed that all logging functions have file/line/function data as template parameters. This will create insane symbol bloat. While I can understand desire to use some nicer variadic argument API providing at least one log function that it simplistic but moves all compile-time data to run-time default argument is absolutely necessary for me to consider this viable."I do not consider that a problem. The benefit is much higher than the cost of the bigger binary. This has already been a long conversation on some previous thread.
Sep 09 2014
On 9/9/14, 12:38 PM, Robert burner Schadek wrote:On Saturday, 30 August 2014 at 02:18:30 UTC, Dicebot wrote:There may be a miscommunication here. In short: void fun(int x, string f = __FILE__)(double y); can be replaced with: void fun(int x)(double y, string f = __FILE__); Both work and the second produces fewer instantiations. Andrei"... have noticed that all logging functions have file/line/function data as template parameters. This will create insane symbol bloat. While I can understand desire to use some nicer variadic argument API providing at least one log function that it simplistic but moves all compile-time data to run-time default argument is absolutely necessary for me to consider this viable."I do not consider that a problem. The benefit is much higher than the cost of the bigger binary. This has already been a long conversation on some previous thread.
Sep 10 2014
On Wednesday, 10 September 2014 at 07:41:49 UTC, Andrei Alexandrescu wrote:There may be a miscommunication here. In short: void fun(int x, string f = __FILE__)(double y); can be replaced with: void fun(int x)(double y, string f = __FILE__); Both work and the second produces fewer instantiations. AndreiBut void fun(int l = __LINE__, A...)(A...); cannot be replaced by void fun(A...)(A..., int l = __LINE__); anyway thanks for reading and for trying to help
Sep 10 2014
On Wednesday, 10 September 2014 at 08:47:47 UTC, Robert burner Schadek wrote:But void fun(int l = __LINE__, A...)(A...); cannot be replaced by void fun(A...)(A..., int l = __LINE__); anyway thanks for reading and for trying to helpAnd this is why I am asking for separate `logRaw` overload that takes pre-formatted string, for those who care.
Sep 10 2014
On 10/09/14 10:47, Robert burner Schadek wrote:But void fun(int l = __LINE__, A...)(A...); cannot be replaced by void fun(A...)(A..., int l = __LINE__);Could we modify the compiler to allow that? Just for the special identifiers __LINE__, __FILE__ and similar. It wouldn't be possible to specify a value for that parameter then. -- /Jacob Carlborg
Sep 10 2014
On Wednesday, 10 September 2014 at 11:39:52 UTC, Jacob Carlborg wrote:On 10/09/14 10:47, Robert burner Schadek wrote:IMO that is overkill, adding another another method that only takes one string as parameter is fine hereBut void fun(int l = __LINE__, A...)(A...); cannot be replaced by void fun(A...)(A..., int l = __LINE__);Could we modify the compiler to allow that? Just for the special identifiers __LINE__, __FILE__ and similar. It wouldn't be possible to specify a value for that parameter then.
Sep 10 2014
On Wednesday, 10 September 2014 at 11:39:52 UTC, Jacob Carlborg wrote:On 10/09/14 10:47, Robert burner Schadek wrote:This is much desired compiler enhancement in my opinion (this template instance bloat is really bad as it impacts not only symbol bloat but also compile times) but trying to get something that works right here and now.But void fun(int l = __LINE__, A...)(A...); cannot be replaced by void fun(A...)(A..., int l = __LINE__);Could we modify the compiler to allow that? Just for the special identifiers __LINE__, __FILE__ and similar. It wouldn't be possible to specify a value for that parameter then.
Sep 10 2014
On Wednesday, 10 September 2014 at 12:14:09 UTC, Dicebot wrote:This is much desired compiler enhancement in my opinion (this template instance bloat is really bad as it impacts not only symbol bloat but also compile times) but trying to get something that works right here and now.killing this special overload, once the compiler does this, should be completely transparent
Sep 10 2014
"Jacob Carlborg" wrote in message news:lupda8$nl1$1 digitalmars.com...Could we modify the compiler to allow that? Just for the special identifiers __LINE__, __FILE__ and similar. It wouldn't be possible to specify a value for that parameter then.IIRC Andrei has a bugzilla open for this.
Sep 10 2014
On 09/10/2014 03:22 PM, Daniel Murphy wrote:"Jacob Carlborg" wrote in message news:lupda8$nl1$1 digitalmars.com...Why? I cannot remember a compiler version where the following did not work: import std.stdio; void fun(A...)(A args, int l = __LINE__){ writeln(args," ",l); } void main(){ fun(1,2,3); } I.e. there is absolutely no issue here.Could we modify the compiler to allow that? Just for the special identifiers __LINE__, __FILE__ and similar. It wouldn't be possible to specify a value for that parameter then.IIRC Andrei has a bugzilla open for this.
Sep 10 2014
On Wednesday, 10 September 2014 at 15:41:49 UTC, Timon Gehr wrote:Why? I cannot remember a compiler version where the following did not work: import std.stdio; void fun(A...)(A args, int l = __LINE__){ writeln(args," ",l); } void main(){ fun(1,2,3); } I.e. there is absolutely no issue here.For every instantiation of of fun there will be a new symbol even when A are the same, because of __LINE__. For Dicebot that is a nogo
Sep 10 2014
"Robert burner Schadek" wrote in message news:wsanssfvnomcwtnqybui forum.dlang.org...Not in that example there won't.import std.stdio; void fun(A...)(A args, int l = __LINE__){ writeln(args," ",l); } void main(){ fun(1,2,3); }For every instantiation of of fun there will be a new symbol even when A are the same, because of __LINE__. For Dicebot that is a nogo
Sep 10 2014
On Wednesday, 10 September 2014 at 15:41:49 UTC, Timon Gehr wrote:Why? I cannot remember a compiler version where the following did not work: import std.stdio; void fun(A...)(A args, int l = __LINE__){ writeln(args," ",l); } void main(){ fun(1,2,3); } I.e. there is absolutely no issue here.For every instantiation of of fun there will be a new symbol even when A are the same, because of __LINE__. For Dicebot that is a nogo
Sep 10 2014
"Timon Gehr" wrote in message news:luprft$29v6$1 digitalmars.com...Why? I cannot remember a compiler version where the following did not work: import std.stdio; void fun(A...)(A args, int l = __LINE__){ writeln(args," ",l); } void main(){ fun(1,2,3); } I.e. there is absolutely no issue here.Hmm, do it does. Maybe I was thinking of this: https://issues.dlang.org/show_bug.cgi?id=2599
Sep 10 2014
On Wednesday, 10 September 2014 at 15:41:49 UTC, Timon Gehr wrote:On 09/10/2014 03:22 PM, Daniel Murphy wrote:This is new to me - I can definitely remember trying it and failing ~ 1-2 years ago."Jacob Carlborg" wrote in message news:lupda8$nl1$1 digitalmars.com...Why? I cannot remember a compiler version where the following did not work: import std.stdio; void fun(A...)(A args, int l = __LINE__){ writeln(args," ",l); } void main(){ fun(1,2,3); } I.e. there is absolutely no issue here.Could we modify the compiler to allow that? Just for the special identifiers __LINE__, __FILE__ and similar. It wouldn't be possible to specify a value for that parameter then.IIRC Andrei has a bugzilla open for this.
Sep 10 2014
Am 10.09.2014 17:41, schrieb Timon Gehr:On 09/10/2014 03:22 PM, Daniel Murphy wrote:Except that it unfortunately doesn't do what is intended: import std.stdio; void fun(A...)(A args, int l = __LINE__){ writeln(args," ",l); } void main(){ fun(10,11); } output: 10 11 expected: 1011 3"Jacob Carlborg" wrote in message news:lupda8$nl1$1 digitalmars.com...Why? I cannot remember a compiler version where the following did not work: import std.stdio; void fun(A...)(A args, int l = __LINE__){ writeln(args," ",l); } void main(){ fun(1,2,3); } I.e. there is absolutely no issue here.Could we modify the compiler to allow that? Just for the special identifiers __LINE__, __FILE__ and similar. It wouldn't be possible to specify a value for that parameter then.IIRC Andrei has a bugzilla open for this.
Sep 10 2014
On 09/10/2014 08:18 PM, Sönke Ludwig wrote:Am 10.09.2014 17:41, schrieb Timon Gehr:Oops! Touché! Thanks. While the code indeed works, there actually _is_ an issue here. :o) (It is even more embarrassing seeing that I have actually built my own implementation of IFTI and it actually matches DMD's behaviour in this case.)On 09/10/2014 03:22 PM, Daniel Murphy wrote:Except that it unfortunately doesn't do what is intended: import std.stdio; void fun(A...)(A args, int l = __LINE__){ writeln(args," ",l); } void main(){ fun(10,11); } output: 10 11 expected: 1011 3"Jacob Carlborg" wrote in message news:lupda8$nl1$1 digitalmars.com...Why? I cannot remember a compiler version where the following did not work: import std.stdio; void fun(A...)(A args, int l = __LINE__){ writeln(args," ",l); } void main(){ fun(1,2,3); } I.e. there is absolutely no issue here.Could we modify the compiler to allow that? Just for the special identifiers __LINE__, __FILE__ and similar. It wouldn't be possible to specify a value for that parameter then.IIRC Andrei has a bugzilla open for this.
Sep 10 2014
On 9/10/14, 11:46 AM, Timon Gehr wrote:Oops! Touché! Thanks. While the code indeed works, there actually _is_ an issue here. :o)Please bugzillize. Thanks! -- Andrei
Sep 10 2014
On 9/10/14, 1:47 AM, Robert burner Schadek wrote:On Wednesday, 10 September 2014 at 07:41:49 UTC, Andrei Alexandrescu wrote:One possibility is to have the first function be a one-liner that forwards to another. That way there will be less code bloating. void fun(uint l = __LINE__, A...)(A... as) { funImpl(l, as); } private void funImpl(A...)(uint line, A...) { ... bulk of the code goes here ... } AndreiThere may be a miscommunication here. In short: void fun(int x, string f = __FILE__)(double y); can be replaced with: void fun(int x)(double y, string f = __FILE__); Both work and the second produces fewer instantiations. AndreiBut void fun(int l = __LINE__, A...)(A...); cannot be replaced by void fun(A...)(A..., int l = __LINE__); anyway thanks for reading and for trying to help
Sep 10 2014
On Wednesday, 10 September 2014 at 16:34:06 UTC, Andrei Alexandrescu wrote:One possibility is to have the first function be a one-liner that forwards to another. That way there will be less code bloating. void fun(uint l = __LINE__, A...)(A... as) { funImpl(l, as); } private void funImpl(A...)(uint line, A...) { ... bulk of the code goes here ... }Those are already small functions AFAIK (I was speaking about symbol bloat, not code bloat). It does not help with compilation issue though - each logging call creates a totally new template instance which means allocating new object for DMD internal representation and running semantic phase for it. And mature applications can have thousands of logging calls. I have yet to run tests to see actual impact but it concerns me from the pure DMD internals point of view.
Sep 10 2014
On 09/10/2014 06:54 PM, Dicebot wrote:On Wednesday, 10 September 2014 at 16:34:06 UTC, Andrei Alexandrescu wrote:Another possibility would be to fix this bug, but the mechanism isn't particularly elegant nor efficient: https://issues.dlang.org/show_bug.cgi?id=13455 :o)One possibility is to have the first function be a one-liner that forwards to another. That way there will be less code bloating. void fun(uint l = __LINE__, A...)(A... as) { funImpl(l, as); } private void funImpl(A...)(uint line, A...) { ... bulk of the code goes here ... }Those are already small functions AFAIK (I was speaking about symbol bloat, not code bloat). It does not help with compilation issue though - each logging call creates a totally new template instance which means allocating new object for DMD internal representation and running semantic phase for it. And mature applications can have thousands of logging calls. I have yet to run tests to see actual impact but it concerns me from the pure DMD internals point of view.
Sep 10 2014
On Wednesday, 10 September 2014 at 16:54:14 UTC, Dicebot wrote: so the current version has one template args log functions that take __LINE__ and friends as normal parameter. I think that was the last complaint, please correct me if I'm wrong. So next round?
Sep 16 2014
Am Tue, 16 Sep 2014 21:22:36 +0000 schrieb "Robert burner Schadek" <rburners gmail.com>:On Wednesday, 10 September 2014 at 16:54:14 UTC, Dicebot wrote: =20 so the current version has one template args log functions that=20 take __LINE__ and friends as normal parameter. =20 I think that was the last complaint, please correct me if I'm=20 wrong.WAT?So next round?Hell no! Am Mon, 15 Sep 2014 22:33:45 +0000 schrieb "Robert burner Schadek" <rburners gmail.com>:again, the idea of std.logger is not to give you everything,=20 because nobody knows what that even is, the idea is to make it=20 possible to do everything and have it understandable later and=20 use transparentlyI understand that part Robert, and already made use of that flexibility. But you use this to play down any concerns about the thread safety of the infrastructure you wrote and finally get std.logger accepted and merged.the threading behavior has been clarified in the api docs.You can't just clarify it in the docs. It requires actual code to work both ways. =20the (a)synchronicity guarantees is part of the concrete Logger=20 impl. the Logger api does not force synchronize or asynchronize=20 behavior, it allows both to be implemented by every subclass of=20 Logger.All access to global state has to be synchronized before we can safely do so, and std.logger doesn't even attempt to in its current state! Some examples: SITUATION: isLoggingEnabled(LogLevel ll, LogLevel loggerLL, LogLevel globalLL, lazy bool condition) { =E2=80=A6 return ll >=3D globalLL && ll >=3D loggerLL && globalLL !=3D LogLevel.off && loggerLL !=3D LogLevel.off && condition } property LogLevel globalLogLevel() trusted nogc { return globalLogLevelImpl(); } private ref LogLevel globalLogLevelImpl() trusted nogc { static __gshared LogLevel ll =3D LogLevel.all; return ll; } is called like this: isLoggingEnabled(stdlog.logLevel, stdlog.logLevel, globalLogLevel, condition); Inside `isLoggingEnabled`, we can expect condition to be evaluated in the context of the calling thread, but the three log level variables passed in create a race condition. Imagine another thread sets `stdlog.logLevel` from warning to error during a logging call. Inside `isLoggingEnabled` you'd now get: return LogLevel.warning >=3D globalLL && LogLevel.warning >=3D LogLevel.error && globalLL !=3D LogLevel.off && loggerLL !=3D LogLevel.off && condition This will unconditionally return false of course. The `stdlog` is now at log level warning AND error at the same time. WAT? EFFECT: Every blue moon a log message will be swallowed by std.logger. SITUATION: private Mutex __stdloggermutex; static this() { __stdloggermutex =3D new Mutex; } property ref Logger stdlog() trusted { static __gshared bool once; static __gshared Logger logger; static __gshared ubyte[__traits(classInstanceSize, FileLogger)] buffer; __stdloggermutex.lock(); scope(exit) __stdloggermutex.unlock(); if (!once) { once =3D true; logger =3D emplace!FileLogger(buffer, stderr, globalLogLevel()); } return logger; } Every thread will now create its own thread local mutex to protect access to global state. EFFECT: ** This protects exactly nothing. ** Write instead: __gshared private Mutex __stdloggermutex; shared static this() { __stdloggermutex =3D new Mutex; } If you need help with multi-threading please ask either here or on IRC. I have found that we have some people in the community that can explain even the fine details of atomic fences. SITUATION: We set the global log level through `globalLogLevel`: property void globalLogLevel(LogLevel ll) trusted { if (stdlog !is null) { stdlog.logLevel =3D ll; } globalLogLevelImpl =3D ll; } What you tried here, was to set the global log level in case we don't have `stdlog` initialized already, because during its creation it will pick up the global log level. Now `globalLogLevelImpl =3D ll;` will never be executed, because inside the `stdlog` property function, it is initialized and thus `stdlog !is null` will always be true. Unless the user sets `stdlog` to null, which I assume is invalid, since it creates fuzzy semantics: The first time `stdlog` is encountered to be null it is set to a FileLogger, any other time it stays null. EFFECT: There is no synchronization around the access to the stdlog. D as far as I know doesn't require that machine word reads/writes are atomic, so in theory you could get a `stdlog` where one half is an old value and the other a new one. That won't happen on ARM and x86, but I thought I'd mention. Much more importantly though another thread could change `stdlog` between `stdlog !is null` and `stdlog.logLevel =3D ll;`. Assuming you want to protect all of the global state with `__stdloggermutex`: property void globalLogLevel(LogLevel ll) trusted { synchronized(__stdloggermutex) { // TODO: stdlog will always initialize itself. // So remove the check? if (stdlog !is null) { stdlog.logLevel =3D ll; } globalLogLevelImpl =3D ll; } } SITUATION: There are 12(!) log methods in the Logger class that call `beginLogMsg` and `finishLogMsg`, which are not thread-safe. We could either override all 12 log methods, which have a complex signature and a lot of boiler plate code or just those two plus `logMsgPart`. The implementations would look very similar if all they want to be is thread safe: protected void beginLogMsg(string file, int line, string funcName, string prettyFuncName, string moduleName, LogLevel logLevel, Tid threadId, SysTime timestamp, Logger logger) trusted { // Don't lock anything if we statically disabled logs static if (isLoggingActive()) { // no 2nd thread may begin logging this.mutex.lock(); // something may go wrong in super's method scope (failure) this.mutex.unlock(); super.beginLogMsg(file, line, funcName, prettyFuncName, moduleName, logLevel, threadId, timestamp, logger); } } protected void logMsgPart(const(char)[] msg) { // don't mess with the mutex outside of enabled logging static if (isLoggingActive()) { // something may go wrong in super's method scope (failure) this.mutex.unlock(); super.logMsgPart(msg); } } protected void finishLogMsg() { // don't mess with the mutex outside of enabled logging static if (isLoggingActive()) { // in any case unlock the mutex afterwards scope (exit) this.mutex.unlock(); super.finishLogMsg() } } EFFECT: The above is a minimum requirement to make Logger thread safe and I think it is easy to forget a static-if or the conditions under which to unlock the mutex. It would be nicer if std.logger was already thread safe to begin with, because it is today common to deal with more than one thread. Also the implementation above has two issues: 1) It cannot be used as a base class, because as an implementation detail it already encapsulates the use of `Appender` which will use the GC. 2) I think it is bad to split up locking and unlocking a mutex over the course of three methods if it is avoidable. So my conclusion is to be able to have a reusable thread safe Logger, which doesn't depend on the GC, it is necessary to pull the thread safety code one level up into the 12 log methods. HINT: Since the 3 methods are protected, it might be an idea to also move the static-if outside of them, so they wont get compiled in at all when logging is statically disabled. That's sort of DRY and will force any call to them to also be statically checked for `static if (isLoggingEnabled())`.) HINT: Maybe the abstract base class should not contain `protected Appender!string msgAppender;` ? SITUATION: abstract class Logger { =E2=80=A6 void delegate() fatalHandler; } EFFECT: Since a delegate consists of two pointers, it will always be set in two memory operations, no matter the architecture. If it is called in one thread while being set in another, it can have a context that doesn't match the function pointer. E.g. you might be calling car.explode(); instead of string.explode(); This is not guaranteed to be a complete list of the issues, but you get the idea. Even if the likelihood of some things I mentioned that could happen is small, they are still errors in the design. And since I am very pedantic about thread safety and want to see these addressed. The other thing is that since you didn't put thought into how std.logger will work in a multi-threaded environment, it is likely the API doesn't make it particularly easy to build on. (See above for suggestions to move thread safety up one level). Also I'm still missing a statement on recursion. How does std.logger deal with e.g. error/warning/... recursively calling itself? P.S.: This was my most thorough review of any Phobos code yet. I guess that means that I'm actually interested in it and feel that it is sorely missing! So thank you for designing this. It is a nice and simple single-threaded standard logging framework aside from the threading issues. --=20 Marco
Sep 18 2014
On Friday, 19 September 2014 at 05:25:18 UTC, Marco Leise wrote:WAT?before every voting there is a review and I guess you started that. I will address the thread-safety sufficiently in the next incarnation. Thank you for taking the timeSo next round?Hell no!
Sep 19 2014
Am Fri, 19 Sep 2014 09:26:59 +0000 schrieb "Robert burner Schadek" <rburners gmail.com>:On Friday, 19 September 2014 at 05:25:18 UTC, Marco Leise wrote::)WAT?before every voting there is a review and I guess you started that.So next round?Hell no!I will address the thread-safety sufficiently in the next incarnation.Ok, thank you. If you get stuck or need a another review, just drop me a mail. 4 eyes see more than 2. I'd even do the changes I had in mind myself and create a pull request if you don't mind. By the way, does anyone else use std.experimental.logger yet? Dicebot?Thank you for taking the timeYou're welcome. I'm really looking forward to this project. This is the kind of component that makes libraries mix and match and helps D grow. -- Marco
Sep 19 2014
On Friday, 19 September 2014 at 11:48:28 UTC, Marco Leise wrote:Ok, thank you. If you get stuck or need a another review, just drop me a mail. 4 eyes see more than 2. I'd even do the changes I had in mind myself and create a pull request if you don't mind.PRs are most welcomeThank you for taking the timeYou're welcome. I'm really looking forward to this project. This is the kind of component that makes libraries mix and match and helps D grow.
Sep 19 2014
Am Fri, 19 Sep 2014 15:12:34 +0000 schrieb "Robert burner Schadek" <rburners gmail.com>:PRs are most welcomeOk, I'm working on it. From the looks of it I will iterate a bit on the code and create one massive pull request with a lot of smaller commits to make it comprehensible. -- Marco
Sep 19 2014
On Friday, 19 September 2014 at 11:48:28 UTC, Marco Leise wrote:By the way, does anyone else use std.experimental.logger yet? Dicebot?No, I provide purely management service here, aggregating reviews/opinions of other community members.
Sep 20 2014
On 9/19/14, 2:26 AM, Robert burner Schadek wrote:On Friday, 19 September 2014 at 05:25:18 UTC, Marco Leise wrote:Nice, thanks! -- AndreiWAT?before every voting there is a review and I guess you started that. I will address the thread-safety sufficiently in the next incarnation. Thank you for taking the timeSo next round?Hell no!
Sep 19 2014
On Tuesday, 16 September 2014 at 21:22:37 UTC, Robert burner Schadek wrote:On Wednesday, 10 September 2014 at 16:54:14 UTC, Dicebot wrote: so the current version has one template args log functions that take __LINE__ and friends as normal parameter. I think that was the last complaint, please correct me if I'm wrong. So next round?Once you feel that thread safety concerns are addressed please write me an e-mail. I am currently on vacation with irregular internet access so may miss regular NG post.
Sep 19 2014
On Saturday, 30 August 2014 at 02:16:55 UTC, Dicebot wrote:============================== Martin Nowak ============================== "Support duck-typing for the log functions. Logger should be a concept and log functions should be free-standing UFCS functions that take any `isLogger!T`. To support a global `defaultLog` variable, you could add a Logger interface and a loggerObject shim. See http://dlang.org/phobos/std_range.html#inputRangeObject for this a pattern." Neither seem to be addressed nor countered.Overly complicated IMO
Sep 08 2014
Am Mon, 08 Sep 2014 11:17:48 +0000 schrieb "Robert burner Schadek" <rburners gmail.com>:On Saturday, 30 August 2014 at 02:16:55 UTC, Dicebot wrote:This may sound surprising, but I believe if we want to make Phobos consistent and give no incentive to roll your own stuff, we should do this for a lot of APIs. Without going into depth (but we could) there are good reasons to use classes and there are good reasons to use duck typing structs. Another API where this mixed scheme would apply are streams. By using function templates with `if (isLogger!T)` and an abstract class Logger, it will only get instantiated once for all derived classes reducing template bloat, while allowing custom instantiations for logger structs to avoid virtual function calls or GC issues. So I agree with Martin. It is a great way to bring the two camps together without major casualties. -- Marco============================== Martin Nowak ============================== "Support duck-typing for the log functions. Logger should be a concept and log functions should be free-standing UFCS functions that take any `isLogger!T`. To support a global `defaultLog` variable, you could add a Logger interface and a loggerObject shim. See http://dlang.org/phobos/std_range.html#inputRangeObject for this a pattern." Neither seem to be addressed nor countered.Overly complicated IMO
Sep 08 2014
On Monday, 8 September 2014 at 12:36:29 UTC, Marco Leise wrote:This may sound surprising, but I believe if we want to make Phobos consistent and give no incentive to roll your own stuff, we should do this for a lot of APIs. Without going into depth (but we could) there are good reasons to use classes and there are good reasons to use duck typing structs. Another API where this mixed scheme would apply are streams. By using function templates with `if (isLogger!T)` and an abstract class Logger, it will only get instantiated once for all derived classes reducing template bloat, while allowing custom instantiations for logger structs to avoid virtual function calls or GC issues. So I agree with Martin. It is a great way to bring the two camps together without major casualties.I think the template bloat argument is invalid as __LINE__ and friends are passed as template arguments to allow write and writef type logging. Anyway I will try to make them free standing
Sep 08 2014
On Monday, 8 September 2014 at 13:20:27 UTC, Robert burner Schadek wrote:On Monday, 8 September 2014 at 12:36:29 UTC, Marco Leise wrote:I think the template bloat argument is invalid as __LINE__ and friends are passed as template arguments to allow write and writef type logging. Anyway I will try to make them free standingThe biggest problem I have currently with this that you, or at least I, can not override the free standing function. void log(L)(ref L logger) if(isLogger!L) { ... } will match always and if I create void log(L)(ref L logger) if(isMySpecialLogger!L) { ... } both match and thats a nogo
Sep 08 2014
Am Mon, 08 Sep 2014 13:37:02 +0000 schrieb "Robert burner Schadek" <rburners gmail.com>:On Monday, 8 September 2014 at 13:20:27 UTC, Robert burner Schadek wrote:You are right, this benefit of classes doesn't apply here.On Monday, 8 September 2014 at 12:36:29 UTC, Marco Leise wrote:I think the template bloat argument is invalid as __LINE__ and friends are passed as template arguments to allow write and writef type logging.Ok, no matter what the outcome is, I'll see if I can write a simple file logger that I can use in RAII struct dtors (where neither allocations nor throwing seem to be an issue) and that has a fallback to writing to stderr. I wrote earlier that I would want a fallback logger if writing via the network fails or the disk is full, but maybe this logic can be implemented inside a logger implementation. I haven't actually tried your API yet! -- MarcoAnyway I will try to make them free standingThe biggest problem I have currently with this that you, or at least I, can not override the free standing function. void log(L)(ref L logger) if(isLogger!L) { ... } will match always and if I create void log(L)(ref L logger) if(isMySpecialLogger!L) { ... } both match and thats a nogo
Sep 08 2014
On Monday, 8 September 2014 at 14:49:06 UTC, Marco Leise wrote:Ok, no matter what the outcome is, I'll see if I can write a simple file logger that I can use in RAII struct dtors (where neither allocations nor throwing seem to be an issue) and that has a fallback to writing to stderr. I wrote earlier that I would want a fallback logger if writing via the network fails or the disk is full, but maybe this logic can be implemented inside a logger implementation. I haven't actually tried your API yet!That should be a no-brainer just have a look at FileLogger and start from there
Sep 08 2014
On Saturday, 30 August 2014 at 02:11:49 UTC, Dicebot wrote:"API must specify a strong stance on threading, whatever the form it takes" Does not seem to be addressed at all. At least I see no mentions of it in core.d documentation and logger instance itself is plain __gshared thing.I'm not a "voter" as far as I know, but I suggest that Logger is formally documented to be not-thread-safe, and that it is the responsibility of subclasses to provide thread safety. Actual Logger's can do so easily by overloading beginLogMsg/logMsgPart/finishLogMsg and not using a shared class variable between calls. Loggers could also remain thread-local but overload writeLogMsg to dispatch the result to thread-safe I/O. The latter is the path I have chosen currently for log4d (https://github.com/klamonte/log4d). (That may change in the future if there is memory pressure from too many thread-local logger instances.)"We need to hammer out how this will work inside libraries. If my app is using multiple libraries I need to know I have full control of how they log and where (), and if I write libraries I need to include logging that will not affect performance or added dependencies.This is a task for a fuller backend, not the std.logger frontend. std.logger should be "mechanism", interfacing multiple libraries together requires "policy"."Logger should include a shared Logger, or include it in the interface for outside libraries to handle the implementation. There will be libraries that thread internally and will need to support shared logging." Is not addressed.stdlog is global and the default implementation is thread-safe by way of FileLogger mutex-locking its writes. It should either be documented that stdlog is always global and it is up to subclasses or logging backends to make stdlog thread-safe, or Logger should be made thread-safe by default by eliminating it's header and msgAppender fields. I'm not sure either way which is better. I don't like the idea that libraries A, B, and C will just blindly use stdlog and hope for the best. If they are "logging" (and not "tracing", for which I hope D evolves a trace attribute) then they should be logging by category/name, which is a job for something like log4d. But Logger's don't have names. Perhaps the better solution would be a convention for libraries to always use a "static Logger Logger.getLogger(string category)" function, for which the default simply ignores category and returns stdlog. "Logger.setGetLoggerFunction(...)" could be provided for backends to change this behavior on application startup, assuming they can guarantee that they can call this function before various libraries have gotten references to stdlog.
Aug 30 2014
On Saturday, 30 August 2014 at 02:11:49 UTC, Dicebot wrote:==================================== Jakob Ovrum ==================================== "The *API* must support minimal dynamic memory allocation for the normal execution path. However, theoretical *implementation* changes that reduce memory allocation are not a deal-breaker." This seems to be addressed but though it is desired to verify it via nogc unittest block which uses stub no-op logger (to verify that nothing in between allocates). One place were GC allocations is unavoidable is core.d:1628 - it will always create FileLogger first and allow assigning custom one later. Is there any way to circumvent it?Yes - split the `stdlog` property into a getter and a setter. Then if the setter is called first (with a non-null reference), the getter never gets to allocate the default instance. I pointed this out in a line comment before, but I guess it disappeared due to the name change... Also, as I said in the line comment, it doesn't need to GC-allocate, it can allocate in global memory or TLS using emplace (which of them is appropriate depends on the threading model, I guess...). If Andrei's reference-counting suggestion is implemented, then depending on the details, it's possible that the default logger could be allocated on the C heap instead of the GC heap as well, managed by RC.
Aug 30 2014
On Saturday, 30 August 2014 at 02:11:49 UTC, Dicebot wrote:On Tuesday, 26 August 2014 at 21:04:28 UTC, Robert burner Schadek wrote: ==================================== Jakob Ovrum ==================================== "The *API* must support minimal dynamic memory allocation for the normal execution path. However, theoretical *implementation* changes that reduce memory allocation are not a deal-breaker." This seems to be addressed but though it is desired to verify it via nogc unittest block which uses stub no-op logger (to verify that nothing in between allocates). One place were GC allocations is unavoidable is core.d:1628 - it will always create FileLogger first and allow assigning custom one later. Is there any way to circumvent it? "API must specify a strong stance on threading, whatever the form it takes" Does not seem to be addressed at all. At least I see no mentions of it in core.d documentation and logger instance itself is plain __gshared thing. $ grep -R -n "shared" std/experimental/logger/ std/experimental/logger/core.d:1625: static __gshared Logger logger; std/experimental/logger/core.d:1635: static __gshared LogLevel ll = LogLevel.all; Does not seem enough for sure.I working on this"This one might seem unnecessarily strict, but I think the fact that Logger is a class and not an interface smells of poor design. I might still be convinced that having it as a class is justified, but my current stance is that it must be an interface." Neither does seem to be addressed nor I can find any comment on why it is not going to be addressed.Every Logger has to have a LogLevel, interfaces won't work there==================================== Francesco Cattoglio ==================================== "As far as I undestood, there's no way right now to do logging without using the GC. And that means it is currently impossible to log inside destructor calls. That is a blocker in my book." First part partially addressed - missing nogc nothrow logger implementation out of the box. Considering this request does not go very well with current language implementation it may be ignored for now but official stance about it must be clearly documented.at least for logf nothrow will not work because of a wrong formatting string or args. log can not be nothrow because custom toString for structs and class are allowed. nogc is not possible because of custom toString that won't fix, but for default types it is nogc.==================================== Byron Heads ==================================== "Logger should include a shared Logger, or include it in the interface for outside libraries to handle the implementation. There will be libraries that thread internally and will need to support shared logging." Is not addressed.See Jakob Ovrun
Sep 08 2014
Am Mon, 08 Sep 2014 11:06:42 +0000 schrieb "Robert burner Schadek" <rburners gmail.com>:=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D==3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3DFrancesco Cattoglio =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=It is fairly obvious that the next GC implementation needs to allow allocations during a sweep. Maybe we should just assume that it already works ? --=20 Marco"As far as I undestood, there's no way right now to do logging without using the GC. And that means it is currently impossible to log inside destructor calls. That is a blocker in my book." First part partially addressed - missing nogc nothrow logger=20 implementation out of the box. [=E2=80=A6]=20 at least for logf nothrow will not work because of a wrong=20 formatting string or args. log can not be nothrow because custom=20 toString for structs and class are allowed. =20 nogc is not possible because of custom toString =20 that won't fix, but for default types it is nogc.
Sep 08 2014
On Monday, 8 September 2014 at 11:06:44 UTC, Robert burner Schadek wrote:It should be possible to provide custom implementation that throws ad Error for those cases (and thus fits the requirements) and `toString` has sink-based overload. Are there any reason why it doesn't help?First part partially addressed - missing nogc nothrow logger implementation out of the box. Considering this request does not go very well with current language implementation it may be ignored for now but official stance about it must be clearly documented.at least for logf nothrow will not work because of a wrong formatting string or args. log can not be nothrow because custom toString for structs and class are allowed. nogc is not possible because of custom toString that won't fix, but for default types it is nogc.
Sep 08 2014
On Monday, 8 September 2014 at 22:54:36 UTC, Dicebot wrote:catching an Exception from formattedWrite just to throw an Error and thus allowing nothrow is just silly IMO. sink-based overloads are nice but we don't write the toString methods of the user and so can not be sure that they are nogc.nogc is not possible because of custom toString that won't fix, but for default types it is nogc.It should be possible to provide custom implementation that throws ad Error for those cases (and thus fits the requirements) and `toString` has sink-based overload. Are there any reason why it doesn't help?
Sep 09 2014
Seeing how MultiLogger passes on the payload to its child loggers by ref, I tried to make it const, so that no Logger implementation can "correct" any of the values and spoil it for the others in the list. Then I noticed, that isn't possible because the payloads contain indirections and one logger takes payloads apart into separate variables (FileLogger) while others build payloads from separate variables. Catch 22. You cannot have: protected void beginLogMsg(string file, int line, string funcName, string prettyFuncName, string moduleName, LogLevel logLevel, Tid threadId, SysTime timestamp, Logger logger) trusted { static if (isLoggingActive) { header =3D LogEntry(file, line, funcName, prettyFuncName, moduleName, logLevel, threadId, timestamp, null, logger); } } and override void writeLogMsg(const ref LogEntry payload) { this.beginLogMsg(payload.file, payload.line, payload.funcName, payload.prettyFuncName, payload.moduleName, payload.logLevel, payload.threadId, payload.timestamp, payload.logger); =E2=80=A6 } . Also I wonder if Tid is the correct information to pass in. It is actually just an MBox from std.concurrency. The real thread handle is the Thread, which also contains its name, which might be more useful for logging. What do you think? --=20 Marco
Sep 20 2014
On Saturday, 20 September 2014 at 10:24:30 UTC, Marco Leise wrote:Also I wonder if Tid is the correct information to pass in. It is actually just an MBox from std.concurrency. The real thread handle is the Thread, which also contains its name, which might be more useful for logging. What do you think?See also https://github.com/D-Programming-Language/phobos/pull/2482 For std.log I think Tid more useful because it clearly denotes execution context while thread ID is more of an implementation detail (considering message-passing is promoted as a standard D thing)
Sep 20 2014
Ok, then here are my thread-safety changes for std.logger: https://github.com/burner/logger/pull/19 -- Marco
Sep 20 2014
Moved to: https://github.com/burner/phobos/pull/2 I did some simple benchmark, logging "Hello world" 1_000_000 times with the default logger. (DMD with release settings). Comparing the version before the thread-safety changes with the one afterwards. The timings are: 6.67s and 6.66s - so it is -0.15% slower now. :p Yes, I'm just trying to confuse you. Within margin of error the performance stays the same. The default logger is using lockingTextWriter() for optimum performance. I compared it with a logger I wrote a while ago and which I ported to std.experimental.logger.core.Logger, but extends it by honoring the system locale for terminal output: Assuming LC_ALL=de_DE.iso88591 it * formats the message using Phobos' formattedWrite(...) * converts UTF-8 to UTF-16 * passes it to ICU for normalization (to combine accents) * transcodes the NFC UTF-16 with ICU to system local * uses POSIX write() to dump it to the terminal With all the overhead it still takes only 2.26s for the same 1_000_000 messages. If I use a UTF-8 terminal and skip string conversion it will be 2.03s. So on the one hand it means string transcoding accounts for ~10% and on the other that there is 228% overhead with the default logger. :) Some of which might be low hanging fruit. But that should not be part of this review (which is about API). It was just an observation I wanted to share. -- Marco
Sep 21 2014