Apex Logging Using Static Resources

Define the Error messages detail in json format as static resource

[{
	"id": "REQUESTED_OPERATION_NOT_PERMITTED",
	"code": 1,
	"clientTemplate": "the current rest operation is not permitted for this endpoint",
	"systemTemplate": "the current rest operation is not permitted for this endpoint"
}, {
	"id": "REQUESTED_ID_MISSING_OR_INVALID",
	"code": 2,
	"clientTemplate": "id is missing or invalid for the specific request",
	"systemTemplate": "id is missing or invalid for the specific request Id {0}"
}, {
	"id": "URL_INVALID",
	"code": 3,
	"clientTemplate": "url invalid and does not exist",
	"systemTemplate": "url invalid and does not exist UserId: {0} | Type: {1} | Path: {2} | Body: {3}"
}, {
	"id": "INPUT_JSON_INVALID",
	"code": 4,
	"clientTemplate": "the input json provided is invalid",
	"systemTemplate": "the input json provided is invalid"
}]

Define a ResponseCode class to parse the json into a List of ResponseCodes

global with sharing class ResponseCode {

  public String id { get; set; }
  public Integer code { get; set; }
  public String clientTemplate { private get; set { clientTemplate = value; } }
  public String systemTemplate { private get; set { systemTemplate = value; } }

  public String formattedClientMessage { get; set; }
  public String formattedSystemMessage { get; set; }

  global void formatMessages(List<String> args, Exception ex) {
    if (args != null && args.size() != 0) {
      formattedClientMessage = String.format(clientTemplate, args);
      if (systemTemplate != null) {
        formattedSystemMessage = String.format(systemTemplate, args);
      }
    } else {
      formattedClientMessage = clientTemplate;
      formattedSystemMessage = systemTemplate;
    }
    if (ex != null) {
      if (formattedSystemMessage == null) {
        formattedSystemMessage = formattedClientMessage;
      }
      formattedSystemMessage += ' -> Cause by: ' + ex.getTypeName() + ' - ' + ex.getMessage() + '. Cause trace: ' + ex.getStackTraceString();
    }
  }

  global ResponseCode copy() {
    ResponseCode theNewObj = new ResponseCode();
    theNewObj.id = this.id;
    theNewObj.code = this.code;
    theNewObj.clientTemplate = this.clientTemplate;
    theNewObj.systemTemplate = this.systemTemplate;
    return theNewObj;
  }

	global ResponseCode(){
	}

  global override String toString() {
    return 'ResponseCode(id=' + id + ';code=' + code + ';clientTemplate=' + clientTemplate + ';systemTemplate=' + systemTemplate + ';formattedClientMessage=' + formattedClientMessage + ';formattedSystemMessage=' + formattedSystemMessage + ')';
  }
}

Define a ResponseCode Manager to translate the Codes into a map to get by id

public with sharing class ResponseCodes_Mgr{

	private static Map<String, ResponseCode> itsResponseCodes = new Map<String, ResponseCode>();

	static {
    try {
      StaticResource theCodesSrc = [SELECT Id, Body FROM StaticResource WHERE Name = 'ResponseCode' LIMIT 1];
      if (theCodesSrc != null) {
    		String theCodesJSON = theCodesSrc.Body.toString();
        List<ResponseCode> theCodesList = (List<ResponseCode>) JSON.deserialize(theCodesJSON, List<ResponseCode>.class);
        for (ResponseCode theCode: theCodesList) {
          itsResponseCodes.put(theCode.id, theCode);
        }
        System.debug('Loaded ' + itsResponseCodes.size() + ' response codes into static map');
      } else {
        System.debug(LoggingLevel.ERROR, 'Cannot query ResponseCode static resource from DB');
      }
    } catch (Exception ex) {
      System.debug(LoggingLevel.ERROR, 'ERROR loading response codes: ' + ex.getMessage());
    }

	}

  public static ResponseCode getCode(String anID) {
    return getCode(anID, null, null);
  }

  public static ResponseCode getCode(String anID, Exception anExp) {
    return getCode(anID, anExp, null);
  }

  public static ResponseCode getCode(String anID, List<String> args) {
    return getCode(anID, null, args);
  }

  public static ResponseCode getCode(String anID, Exception anExp, List<String> args) {
    // make a copy so that the caller can do whatever with the object
    // multiple callers might use same ID with different args list
    ResponseCode theCode = itsResponseCodes.get(anID);
    if (theCode == null) {
      theCode = itsResponseCodes.get('UNEXPECTED_RESPONSE_CODE').copy();
      List<String> theArgs = new List<String>();
      theArgs.add(anID);
      if (args != null) {
        theArgs.add(args + '');
      }
      theCode.formatMessages(theArgs, anExp);
      System.debug(LoggingLevel.ERROR, 'Unknown response code ' + anID + '. Returning UNEXPECTED_RESPONSE_CODE and ignoring args list ' + args);
    } else {
      theCode = theCode.copy();
      theCode.formatMessages(args, anExp);
    }
    return theCode;
  }
}

Catch exceptions and log exceptions to logging provide

}catch (JSONException jsonEx){
  responseCode = ResponseCodes_Mgr.getCode('JSON_SERIALIZATION_FAILED', jsonEx, new List<String>{UserInfo.getUserId(), requestHeaders.get(TRACE_ID_KEY), requestHeaders.get('timestamp'), requestType.name(), request.requestURI, SHOW_BODY && request.requestBody!= null ? request.requestBody.toString() : ''});
  json.setResponseCode(responseCode);
} catch (SearchException searchEx){
  responseCode = ResponseCodes_Mgr.getCode('SEARCH_FAILED', searchEx, new List<String>{UserInfo.getUserId(), requestHeaders.get(TRACE_ID_KEY), requestHeaders.get('timestamp'), requestType.name(), request.requestURI, SHOW_BODY && request.requestBody!= null ? request.requestBody.toString() : ''});
  json.setResponseCode(responseCode);
} catch (CalloutException calloutEx){
  responseCode = ResponseCodes_Mgr.getCode('CALLOUT_FAILED', calloutEx, new List<String>{UserInfo.getUserId(), requestHeaders.get(TRACE_ID_KEY), requestHeaders.get('timestamp'), requestType.name(), request.requestURI, SHOW_BODY && request.requestBody!= null ? request.requestBody.toString() : ''});
  json.setResponseCode(responseCode);  
} catch (DmlException dmlEx){
  responseCode = ResponseCodes_Mgr.getCode('DATABASE_OPERATION_FAILED', dmlEx, new List<String>{UserInfo.getUserId(), requestHeaders.get(TRACE_ID_KEY), requestHeaders.get('timestamp'), requestType.name(), request.requestURI, SHOW_BODY && request.requestBody!= null ? request.requestBody.toString() : ''});
  json.setResponseCode(responseCode);
} catch (SObjectException sobjectEx){
  responseCode = ResponseCodes_Mgr.getCode('SOBJECT_OPERATION_FAILED', sobjectEx, new List<String>{UserInfo.getUserId(), requestHeaders.get(TRACE_ID_KEY), requestHeaders.get('timestamp'), requestType.name(), request.requestURI, SHOW_BODY && request.requestBody!= null ? request.requestBody.toString() : ''});
  json.setResponseCode(responseCode);
  String serializeJson = Rest_Global_Json.instance.serialize(json);
  res.responseBody = Blob.valueof(serializeJson);
} catch (QueryException queryEx){
  responseCode = ResponseCodes_Mgr.getCode('QUERY_OPERATION_FAILED', queryEx, new List<String>{UserInfo.getUserId(), requestHeaders.get(TRACE_ID_KEY), requestHeaders.get('timestamp'), requestType.name(), request.requestURI, SHOW_BODY && request.requestBody!= null ? request.requestBody.toString() : ''});
  json.setResponseCode(responseCode);
} catch (Exception ex){
  responseCode = ResponseCodes_Mgr.getCode('REST_DISPATCHER_FAILED', ex, new List<String>{UserInfo.getUserId(), requestHeaders.get(TRACE_ID_KEY), request.headers.get('timestamp'), requestType.name(), request.requestURI, SHOW_BODY && request.requestBody!= null ? request.requestBody.toString() : ''});
  json.setResponseCode(responseCode);
}