diff --git a/README.md b/README.md index 9a18d0b57f..9df61cad75 100644 --- a/README.md +++ b/README.md @@ -92,6 +92,13 @@ Twilio.setEdge("sydney"); This will result in the `hostname` transforming from `api.twilio.com` to `api.sydney.au1.twilio.com`. +### Enable Debug Logging +In order to enable debug logging, create a configuration file named log4j2.xml that defines the logger at the root level to at least 'debug'. An example of the configuration file can be found [here](src/main/java/com/twilio/example/log4j2.xml). For more configuration options please see the log4j configuration [documentation](https://logging.apache.org/log4j/2.x/manual/configuration.html). +```java +Twilio.init(accountSid, authToken); +Twilio.setLoggerConfiguration("path/to/log4j2.xml"); +``` + ### Environment Variables `twilio-java` supports the credentials, region, and edge values stored in the following environment variables: @@ -139,7 +146,7 @@ try { new PhoneNumber("+15559994321"), // From number "Hello world!" // SMS body ).create(); - + System.out.println(message.getSid()); } catch (final ApiException e) { System.err.println(e); diff --git a/pom.xml b/pom.xml index ed2976911a..20516d147f 100644 --- a/pom.xml +++ b/pom.xml @@ -238,6 +238,16 @@ 3.4.1 test + + org.apache.logging.log4j + log4j-api + 2.14.0 + + + org.apache.logging.log4j + log4j-core + 2.14.0 + @@ -382,4 +392,4 @@ oss-parent 7 - \ No newline at end of file + diff --git a/src/main/java/com/twilio/Twilio.java b/src/main/java/com/twilio/Twilio.java index cb35cf6341..6820838f8c 100644 --- a/src/main/java/com/twilio/Twilio.java +++ b/src/main/java/com/twilio/Twilio.java @@ -12,6 +12,10 @@ import java.util.Objects; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; +import java.io.File; + +import org.apache.logging.log4j.core.LoggerContext; +import org.apache.logging.log4j.LogManager; /** * Singleton class to initialize Twilio environment. @@ -150,6 +154,19 @@ public static synchronized void setEdge(final String edge) { Twilio.edge = edge; } + /** + * Set the logger configuration file path. + * + * @param filePath path to logging configuration file + * @param loggerContext defaults to false to get the appropriate logger context for the caller. + */ + public static synchronized void setLoggerConfiguration(final String filePath, final boolean... loggerContext) { + boolean logContext = (loggerContext.length >= 1) ? loggerContext[0] : false; + LoggerContext context = (org.apache.logging.log4j.core.LoggerContext) LogManager.getContext(logContext); + File file = new File(filePath); + context.setConfigLocation(file.toURI()); + } + /** * Returns (and initializes if not initialized) the Twilio Rest Client. * diff --git a/src/main/java/com/twilio/example/log4j2.xml b/src/main/java/com/twilio/example/log4j2.xml new file mode 100644 index 0000000000..b29b207aca --- /dev/null +++ b/src/main/java/com/twilio/example/log4j2.xml @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/src/main/java/com/twilio/http/TwilioRestClient.java b/src/main/java/com/twilio/http/TwilioRestClient.java index 61acfc6679..fcf91d4ad1 100644 --- a/src/main/java/com/twilio/http/TwilioRestClient.java +++ b/src/main/java/com/twilio/http/TwilioRestClient.java @@ -4,6 +4,12 @@ import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; import java.util.function.Predicate; +import java.util.Map; +import java.util.List; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.apache.logging.log4j.core.LoggerContext; public class TwilioRestClient { @@ -19,6 +25,7 @@ public class TwilioRestClient { private final String region; private final String edge; private final HttpClient httpClient; + private static final Logger logger = LogManager.getLogger(); private TwilioRestClient(Builder b) { this.username = b.username; @@ -50,7 +57,16 @@ public Response request(final Request request) { if (edge != null) request.setEdge(edge); - return httpClient.reliableRequest(request); + logRequest(request); + Response response = httpClient.reliableRequest(request); + logger.debug("status code: " + response.getStatusCode()); + org.apache.http.Header[] responseHeaders = response.getHeaders(); + logger.debug("response headers:"); + for (int i = 0; i < responseHeaders.length; i++) { + logger.debug(responseHeaders[i]); + } + + return response; } public String getAccountSid() { @@ -126,4 +142,29 @@ public TwilioRestClient build() { } } + /** + * Logging debug information about HTTP request. + */ + public void logRequest(final Request request) { + logger.debug("-- BEGIN Twilio API Request --"); + logger.debug("request method: " + request.getMethod()); + logger.debug("request URL: " + request.getUrl()); + final Map> queryParams = request.getQueryParams(); + final Map> headerParams = request.getHeaderParams(); + + if (!queryParams.isEmpty()) { + logger.debug("query parameters: " + queryParams); + } + + if (!headerParams.isEmpty()) { + logger.debug("header parameters: "); + for (String key : headerParams.keySet()) { + if (!key.toLowerCase().contains("authorization")) { + logger.debug(key + ": " + headerParams.get(key)); + } + } + } + logger.debug("-- END Twilio API Request --"); + } + } diff --git a/src/test/java/com/twilio/http/LoggingTest.java b/src/test/java/com/twilio/http/LoggingTest.java new file mode 100644 index 0000000000..9760ff536d --- /dev/null +++ b/src/test/java/com/twilio/http/LoggingTest.java @@ -0,0 +1,59 @@ +package com.twilio.http; + +import com.twilio.Twilio; +import com.twilio.rest.Domains; +import com.twilio.rest.api.v2010.account.Message; +import org.junit.Before; +import org.junit.Test; +import org.junit.Assert; + +import java.io.ByteArrayOutputStream; +import java.io.PrintStream; + +public class LoggingTest { + private ByteArrayOutputStream output; + private PrintStream originalStream; + + @Before + public void setUp() throws Exception { + Twilio.init("AC123", "AUTH TOKEN"); + } + + public void logCapturingSetup() { + output = new ByteArrayOutputStream(); + PrintStream outputStream = new PrintStream(output); + originalStream = System.out; + System.setOut(outputStream); + } + + public void finishLogCapturingSetup(Request request) { + TwilioRestClient twilioRestClient = Twilio.getRestClient(); + twilioRestClient.logRequest(request); + System.out.flush(); + System.setOut(originalStream); + } + + @Test + public void testDebugLogging() { + logCapturingSetup(); + Twilio.setLoggerConfiguration("src/main/java/com/twilio/example/log4j2.xml"); + final Request request = new Request(HttpMethod.GET, Domains.API.toString(), + "/2010-04-01/Accounts/AC123/Messages/MM123.json"); + request.addHeaderParam("Authorization", "authorization value"); + request.addHeaderParam("Test Header", "test value"); + finishLogCapturingSetup(request); + Assert.assertTrue(output.toString().contains("GET")); + Assert.assertFalse(output.toString().contains("Authorization")); + } + + @Test + public void testUsingDefaultConfigurationFileDebugLogging() { + logCapturingSetup(); + final Request request = new Request(HttpMethod.GET, Domains.API.toString(), + "/2010-04-01/Accounts/AC123/Messages/MM123.json"); + request.addHeaderParam("Authorization", "authorization value"); + request.addHeaderParam("Test Header", "test value"); + finishLogCapturingSetup(request); + Assert.assertTrue(output.toString().isEmpty()); + } +}