What is the best practice to persist logs from apex classes, batch jobs, and controllers? We are still in the development stage so we haven't considered LMA. We tried to store it in a custom object. But with this approach, we are not able to persist logs from controllers and constructors as DML operations are not allowed.
If you are building Enterprise ready apps for Enterprise edition and above, use platform event feature
Platform events can be published in apex and subscribed via a simple apex trigger.
Fire a platform event on error and write a trigger to subscribe and store the error in a custom object.
This is an asynchronous action as well so would have less impact on CPU.