Depends on what's causing the error and the language, though as a rule I would often say "all of the above" -- such as in PHP having a singleton object that handles both regular errors and exceptions outputting the correct error codes both client-side (whilst avoiding revealing any details that could be used by crackers) and into a permanent log.
Or in JavaScript where I'll make an object that has my error test conditions as methods which then either console.logs, console.warn, or does a Throw new Error as appropriate to the error in question... whilst also exposing those (with legacy wrappers to a object at the end of document.body for pre-console browsers if needed) log/warn/throw methods so that they can be called by future code if need be whilst maintaining a consistent error behavior.
I actually kind-of worry when people advocate something like a specific error handling method to the exclusion of all others. It begs the question "then why to do the others exist?" -- Like the clowns right now screaming "never use exceptions in PHP" -- RIGHT... tell me another one Josephine.
I've even had some jokers say you should never use "Throw" in JavaScript because it halts scripting execution... well duh, THAT'S WHY I'M USING IT!!!