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);
}

Static and dynamic SOQL queries and best practices

If you are building Dynamic SOQL Queries that can be using for Apex Classes and Batch Apex you can use the Database.query(”) function to build the query:

      private static final String soqlQuery = 'Select id, OwnerId from Account';
      public void updateAccountOwnerByOwnerName(String currentOwnerName, String newOwnerName)
      {
         Map<Account> updateAccountWithNewOwnerName = new Map();
         List<Account> accountsAssignedToCurrentOwner = Database.query(soqlQuery + ' where Owner.Name like \' currentOwnerName + \');
         User getNewOwnerId = new User(Name=newOwnerName);
         for (Account accountsToUpdateOwner : accountsAssignedToCurrentOwner)
         {
           accountsToUpdateOwner.OwnerId = getNewOwnerId.Id;
           updateAccountWithNewOwnerName.put(accountsToUpdateOwner.OwnerId, accountsToUpdateOwner);
         }
        update updateAccountWithNewOwnerName.values();
      }

Non-dynamic soql or static soql looks like:

List<Account> accounts = [select id from account limit 100];

Apex Batch returns Database.QueryLocator or a Iterable.

private String query = 'Select id from Account';
return Database.getQueryLocator(query);

Combining non-dynamic SOQL with dynamic SOQL by converting from [ ] to a String. Using Database.getQueryLocator this can be done:

Database.getQueryLocator([select id from account] + ' where Owner.Name =' + newOwnerName);