5 ms·
> It's absolutely not an anti-pattern if you have appropriate tools to handle different levels of logging, and especially not if you can filter debug output by
by AdieuToLogic 1y ago
> It's absolutely not an anti-pattern if you have appropriate tools to handle different levels of logging, and especially not if you can filter debug output by area.
It is an anti-pattern due to what was originally espoused:
I add logging code, that stays forever. For a major
interface, I'll usually start with INFO level debugging, to
document function entry/exit, with param values.
There is no value for logging "function entry/exit, with param values" when all collaborations succeed and the system operates as intended. Note that service request/response logging is its own concern and is out of scope for this discussion.
Also, you did not address the non-trivial cost implications of voluminous log output.
> You touch on this, but it's a bit strange to me that the default case is assumed to be "all logs all the time".
Regarding the above, production-ready logging libraries such as Logback[0], log4net[1], log4cpp[2], et al, allow for run-time configuration to determine what "areas" will have their entries emitted. So "all logs all the time" is a non sequitur in this context.
What is relevant is the technique identified of emitting execution context when it matters and not when it doesn't. As to your `npm` example, I believe this falls under the scenario I explicitly identified thusly:
... an "unconditionally emit trace logs" environment
(such as local unit/integration tests).
0 - https://logback.qos.ch/ https://logback.qos.ch/
1 - https://logging.apache.org/log4net/index.html https://logging.apache.org/log4net/index.html
2 - https://log4cpp.sourceforge.net/ https://log4cpp.sourceforge.net/
- strken 1y agoI understand that you explained some exceptions to the rule, but I disagree with two things: the assumption of incompetence on the part of geophile to not make logging conditional in some way, and adding the label of "anti-pattern" to something that's evidently got so much nuance to it. > the non-trivial cost implications of voluminous log output If log output is conditional at compile time there are no non-trivial cost implications, and even at runtime the costs are often trivial.
- AdieuToLogic 1y ago> ... I disagree with two things: the assumption of incompetence on the part of geophile to not make logging conditional in some way ... I assumed nothing of the sort. What I did was identify an anti-pattern and describe an alternative which experience has shown to be a better approach. "Incompetence" is your word, not mine. > ... and adding the label of "anti-pattern" to something that's evidently got so much nuance to it. I fail to see the nuance you apparently can see. >> the non-trivial cost implications of voluminous log output > If log output is conditional at compile time there are no non-trivial cost implications, and even at runtime the costs are often trivial. Cloud deployment requires transmission of log entries to one or more log aggregators in order to be known. By definition, this involves network I/O. Network communication is orders of magnitude slower than local I/O. Useless logging of "function entry/exit, with param values" increases pressure on network I/O. Unless logging is allowed to be lossy, which it never is, transmission must be completed when log buffers are near full capacity. Provisioning production systems having excessive logging can often require more resources than those which do not excessively log. Thus disproving: > ... even at runtime the costs are often trivial. When considering the implication of voluminous log output in a production environment.
- strken 1y agoAs I said, conditional. As in, you add logging to your code but you either remove it at compile time or you check your config at run time. By definition, work you don't do is not done.
- TeMPOraL 1y agoConditionals aren't free either, and conditionals - especially compile-time - on logging code are considered by some a bugprone anti-pattern as well. The code that computes data for and assembles your log message may end up executing logic that affects the system elsewhere. If you put that code under conditional, your program will behave differently depending on the logging configuration; if you put it outside, you end up wasting potentially substantial amount of work building log messages that never get used.
- strken 1y agoThis is getting a bit far into the weeds, but I've found that debug output which is disabled by default in all environments is quite safe. I agree that it would be a problem to leave it turned on in development, testing, or staging environments.
- geophile 1y agoYou are very attached to this "voluminous" point. What do you mean by it? As I said, responding to another comment of yours, a distributed system I worked on produced a few GB a day. The logs were rotated daily. They were never transmitted anywhere, during normal operation. When things go wrong, sure, we look at them, and generate even more logging. But that was rare. I cannot stress enough how much of a non-issue log volume was in practice. So I ask you to quantify: What counts (to you) as voluminous, as in daily log file sizes, and how many times they are sent over the network?
- AdieuToLogic 1y ago> You are very attached to this "voluminous" point. What do you mean by it? I mean "a lot" or more specifically; "a whole lot." Here is an exercise which illustrates this. For the purposes here, assume ASCII characters are used for log entries to make the math a bit easier. Suppose the following: Each log statement is 100 characters. Each service invocation emits 50 log statements. Average transactions per second during high usage is 200tps. High usage is on average 2 hours per day. 100 x 50 x 200 x 60 x 60 x 2 = 7_200_000_000 = 7.2GB / day > So I ask you to quantify: What counts (to you) as voluminous, as in daily log file sizes, and how many times they are sent over the network? The quantification is above and regarding log entries being sent over a network - in many production systems, log entries are unconditionally sent to a log aggregator and never stored in a local file system.
- foldr 1y agoThe whole concept of an “anti-pattern” is a discussion ender. It’s basically a signal that one party isn’t willing to consider the specific advantages and disadvantages of a particular approach in a given context.
- geophile 1y ago> There is no value for logging "function entry/exit, with param values" when all collaborations succeed and the system operates as intended. Well, I agree completely, but those conditions are a tall order. The whole point of debugging (by whatever means you prefer) is for those situations in which things don't succeed or operate as intended. If I have a failure, and suspect a major subsystem, I sure do want to see all calls and param values leading up to a failure. In addition to this point, you have constructed a strawman in which logging is on all the time. Have you ever looked at syslog? On my desktop Linux system, output there counts as voluminous. It isn't so much space, or so CPU-intensive that I would consider disabling syslog output (even if I could). The large distributed system I worked on would produce a few GB per day, and the logs were rotated. A complete non-issue. And for the rare times that something did fail, we could turn up logging with precision and get useful information.
- AdieuToLogic 1y ago>> There is no value for logging "function entry/exit, with param values" when all collaborations succeed and the system operates as intended. > Well, I agree completely, but those conditions are a tall order. Every successful service invocation satisfies "all collaborations succeed and the system operates as intended." Another way to state this is every HTTP `1xx`, `2xx`, and `3xx` response code produced by an HTTP service qualifies as such. > The whole point of debugging (by whatever means you prefer) is for those situations in which things don't succeed or operate as intended. Providing sufficient context in the presence of errors, or "situations in which things don't succeed or operate as intended", was addressed thusly: If detailed method invocation history is a requirement, consider using the Writer Monad and only emitting log entries when either an error is detected or in an "unconditionally emit trace logs" environment (such as local unit/integration tests). > If I have a failure, and suspect a major subsystem, I sure do want to see all calls and param values leading up to a failure. See above. > In addition to this point, you have constructed a strawman in which logging is on all the time. No, I addressed your original premise in the context of a production web application, where logging is configured during deployment. See also your own contradiction by previously asserting, "I sure do want to see all calls and param values leading up to a failure." So which is it? Did I construct a strawman "in which logging is on all the time"? Or do you "want to see all calls and param values leading up to a failure", which requires "logging is on all the time"? > Have you ever looked at syslog? This is a strawman. Syslog is a component for logging and has nothing to do with the programs which use it. > The large distributed system I worked on would produce a few GB per day, and the logs were rotated. A complete non-issue. If this is the same system you described in a different comment also in this thread, I identified a standard industry practice of log entries produced by application nodes in a production environment being unconditionally sent to a log aggregator and not stored in a local file system. The reasons for this are well documented.