jongpie / NebulaLogger

The most robust logger for Salesforce. Works with Apex, Lightning Components, Flow, Process Builder & Integrations. Designed for Salesforce admins, developers & architects.

Home Page:https://nebulalogger.com

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Allow changing the logging level on the LogEntryLevelBuilder

TrangOul opened this issue · comments

New Feature Summary

Please make it possible to set the logging level after the LogEntryLevelBuilder instance is created, just like with setRecord or setHttpResponseDetails.

Example usage:

Current:

HttpRequest request = new HttpRequest();
HttpResponse response = new Http().send(request);
if (isSuccess(request)) { // 200 <= statusCode < 300;
	Logger.debug(logTitle).setHttpRequestDetails(request).setHttpResponseDetails(response).addTag(LogUtils.TAG_CALLOUT);
} else {
 	// all the code repeated except different logging level
	Logger.error(logTitle).setHttpRequestDetails(request).setHttpResponseDetails(response).addTag(LogUtils.TAG_CALLOUT);
}

Attempt to avoid repeating logging:

HttpRequest request = new HttpRequest();
LogEntryEventBuilder logBuilder = Logger.debug(logTitle).setHttpRequestDetails(request).addTag(LogUtils.TAG_CALLOUT);
HttpResponse response = new Http().send(request);
logBuilder.setHttpResponseDetails(this.response); //so far, so good; setting response as an additional detail
if (!isSuccess(request)) {
	// logBuilder.setLoggingLevel(System.LoggingLevel.ERROR); // impossible, no such method
	Logger.flushBuffer(); // remove previous success log - and possibly other unsaved logs...
	Logger.error(logTitle).setHttpRequestDetails(request).setHttpResponseDetails(response).addTag(LogUtils.TAG_CALLOUT); // again, repeated code
}

Currently the entryLoggingLevel field in the LogEntryLevelBuilder class is final, so there is no such a setLoggingLevel method.. Is there any reason why?

Hi @TrangOul - there would be some downstream complications with allowing the logging level to be changed after the builder is created. The entry's logging level is used to decide if the builder is added to Logger's buffer & to decide if the method calls in the builder should actually do anything. When the entry logging level doesn't match the user's configured logging level (e.g., the user has logging level INFO, but the entry has FINE), all of the builder methods are essentially no-ops to minimize CPU time - if the logging level then changed later, the builder wouldn't have all of the necessary info set on the LogEntryEvent__e record.

I think you can accomplish your goal in a slightly different way, using an existing method in Logger - Logger.newEntry(). This method takes LoggingLevel enum value as the first parameter, so you can do something like this to minimize repeating your code:

HttpRequest request = new HttpRequest();
HttpResponse response = new Http().send(request);
LoggingLevel entryLoggingLevel = isSuccess(request) ? LoggingLevel.DEBUG : LoggingLevel.ERROR;
Logger.newEntry(entryLoggingLevel, logTitle).setHttpRequestDetails(request).setHttpResponseDetails(response).addTag(LogUtils.TAG_CALLOUT);

Let me know if this approach handles your situation.

That's a nice approach, thanks!
Actually I need to catch two possible errors: errors from callout (response ≠ 200) and Apex exceptions.

Here is the old code, which saved two log entries:

try {
	HttpRequest request = new HttpRequest();
	LogEntryEventBuilder logBuilder = Logger.debug(buildTitle(...)).setHttpRequestDetails(request).addTag(LogUtils.TAG_CALLOUT);
	HttpResponse response = new Http().send(request);
	logBuilder.setHttpResponseDetails(this.response);
	if (!isSuccess(request)) {
		Logger.flushBuffer(); // remove previous success log
		logBuilder = Logger.error(logTitle).setHttpRequestDetails(this.request).setHttpResponseDetails(this.response).addTag(LogUtils.TAG_CALLOUT);
	}
} catch (Exception e) {
	Logger.error(e.getMessage()).setExceptionDetails(e).addTag(LogUtils.TAG_EXCEPTION);
	throw e;
} finally {
	Logger.saveLog();
}

And new code, with a single entry per callout, with all possible details (request, response, exception):

HttpRequest request; // actually these are instance variables,
HttpResponse response; // but for the sake of a minimal example
LoggingLevel entryLoggingLevel = LoggingLevel.DEBUG;
Exception ex;
try {
	request = new HttpRequest();
	response = new Http().send(request);
	if (!isSuccess(response)) {
		entryLoggingLevel = LoggingLevel.ERROR;
	}
} catch (Exception e) {
	entryLoggingLevel = LoggingLevel.ERROR;
	ex = e;
	throw e;
} finally {
	LogEntryEventBuilder logBuilder = Logger.newEntry(entryLoggingLevel, buildTitle(...))
		.setHttpRequestDetails(request)
		.setHttpResponseDetails(response)
		.addTag(LogUtils.TAG_CALLOUT);
	
	if (ex != null) {
		logBuilder.setExceptionDetails(ex).addTag(LogUtils.TAG_EXCEPTION);
	}
	Logger.saveLog();
}

@TrangOul that looks great! Your new code looks much cleaner, I'm glad that the newEntry() method was helpful for this situation.

I'm going to close this issue & mark it as "wontfix" due to the downstream complications I mentioned with allowing the entry logging level to be changed - but please let me know if you need anything else!