Contents

Logs and Errors

Logs and Errors

Generally speaking, in our project, if we strictly divide it according to a hierarchical structure, it is roughly handler, service (which is further subdivided into application in DDD), and domain, dao.

For the dao layer, if an error occurs, we deal with it by directly up-throwing and selectively logging the error, for example, there may be some interfaces that involve parameter validation at the dao layer, manually managing transactions, and so on, which require logging, but the error is still directly up-throwing.

In the service layer, when we encounter errors, they are categorized into two situations: errors within business expectations, and non-business errors.

For the former, we deal with it by predefining various business error codes, converting them to error interface up-throw when encountered, and converting them to resp code by handler to be returned to the client, with optional Warn logs (low-frequency critical scenarios).

For the latter, the error is usually a technical error, which should not be handled by the service itself, but by the caller, so here we play logging + error up-throw. The description here is also not exhaustive, you can refer to the following table for details:

Scene classificationProcessing MethodLog PolicyWhether to throw upwards or notExamples
1. Expected business errorsReturn custom business error typesOptional Warn log (low-frequency critical scenarios) isYesErrUserNotFound
2. Non-critical errors that need to be downgradedSilent processing, return default valuesNo loggingNoDowngrade and check DB when cache expires
3. Infrastructure/Technical errorsWrap the original Error, add business contextMandatory error logYesDatabase connection failed, RPC timeout
4. The original error that needs to be transmitted throughDirectly return the original error without loggingWithout LoggingYesIt is the gorm.ErrRecordNotFound of the DAO layer

What needs to be done at the handler layer is relatively simple. If an error is encountered, it is handled through the unified wrap function: through error.As to determine whether it is a specific business error. If so, retrieve the error code and error message. If not, return a uniform error code and error message.

At the same time, there are two options here: return the unified error message + the description information in err; print the error message only returns a uniform error message. Personally, I prefer the latter. The former is more suitable for Debug environments.