IMO, the OP post has an unfounded sense of hubris. Everyone else's code is bad except for me, who only writes minimal code with no exploits.
Assuming you're fallible and write code with exploits like everyone else, your program will probably have different exploits from mine. An attacker won't be able to target a widely used library and enjoy being able to pick from several targets. Instead, they'll have to tailor an attack for your code base. Each exploit found yields less of a reward, which will frustrate less motivated attackers.
> Instead, they'll have to tailor an attack for your code base.
This misstates the actual threat.
Assume detection of exploits is automated (even if it isn’t completely automated now). Assume exploit code is modularized and passed around on hacker markets, because they are.
Your recommendation only increases the cost to exploit by a small factor, but it also increases the inevitable costs of legitimate usage by possibly a much larger factor (patching the inevitable bugs which are found). Because developers aren’t specializing (in how to efficiently+safely write logging code) bugs both in the designs phase and implementation phase will be higher than in a counterfactual specialization world.
Libraries are not only larger because they are written for more use-cases, but also because they cover more tested edge cases.
But using "don't roll your own crypto" doesn't generalize to using every possible library to avoid writing any code. Down that path lies the madness of leftpad.
Crypto and security protocol implementations are exceptionally difficult to write in a way that avoids all exploits, so, yeah, don't write your own TLS library unless you're willing to fund a team of all the necessary experts which is going to be very difficult.
OTOH a very large number of libraries implement simple things in overly complex ways (sometimes by necessity because a library needs to try to be all things for all people) and can be very easily replaced by small amounts of code that do only what my product needs.
Every third-party library you add is an additional source of bugs, unmaged surprises (e.g. they decide to break their APIs for the lulz), attack surface and constraints. It is wise to weight the benefits against the drawbacks for each library individually before making it part of your code.
At the same time, there's a lot of hubris that goes into the statement "Every third-party library you add is an additional source of bugs, unmaged surprises", but somehow the code you write was typed by God himself.
Everyone points to leftpad madness of dependencies despite the fact that the dominos leading up to leftpad was the work of one very dedicated individual. Despite other languages having the same kind of simple dependency management never having anywhere close to the same issue (like Ruby, on which npm was based). Regardless, the OP doesn't use leftpad as an example; he uses log4j. I agree that log4j had insane defaults, and that's on the maintainers, but the implication is that you should roll your own logging facade and that's something where I wouldn't want to work on a project where all the logging is done through printf (except in probably an embedded environment) or maintain an in-house logging library because the original writer thought it would be "just small amounts of code".
You (everyone) should't allow hubris to drive these decisions, instead make an objective evaluation.
If you're going in saying "I can write this same functionality better than anyone else so I'll just do it", stop and rethink.
Every line of code (to an approximation) adds more potential bugs. So if you pull in a library with a million lines of code, you've added that level of magnitude for possibly future bugs. If you actually need most of those million lines because you use all the features, then you need them. In that case it would be hubris to assume that you can write the same but slightly different million lines and do much better. You can't.
But as other subthreads here point out, often you really use like a thousand lines out of that million line library. If that's you use case, you can reduce your attack surface by 999000 lines of code by writing a few functions of your own, customized to your needs without any unused frills. You don't need a god in your staff, just someone who values the reliability and security that simplicity brings.
> unmanaged surprises
To unpack this statement, I meant that when using a third party library you are now subject to their schedule and roadmap over which you don't have any say or ability to manage it. They might drop a feature you need, or break APIs in a minor release, etc. This is undeniably true, so must be taken into account when doing a risk analysis on depending on some library. Well-run libraries offer a stable platform but tons of libraries are not well-run from a release engineering aspect. Choose carefully and know what you're getting into.
TLS is an example of when you probably would not make that trade-off, but there are lots of other examples where it would make sense.
The same goes for parsing and other complicated operations containing pitfalls.
Honestly, I hope most crypto, parsing, numerics libs, and OS kernels and drivetd were rewritten in Rust and given C, C++, etc. interfaces.