diff --git a/pom.xml b/pom.xml index 54a58519..60b9a16a 100644 --- a/pom.xml +++ b/pom.xml @@ -1,342 +1,361 @@ - - - 4.0.0 - - com.splunk.logging - splunk-library-javalogging - - 1.12.0-SNAPSHOT - - jar - - Splunk Logging for Java - https://dev.splunk.com/goto/sdk-slj - - - Library for structured, semantic logging of Common Information Model compliant events, meant for use with SLF4J. - - - - true - UTF-8 - - - - 2.17.0 - - - 1.2.9 - - - - Default - - true - - - - - maven-compiler-plugin - 3.8.1 - - 8 - 8 - - - - org.apache.maven.plugins - maven-source-plugin - 3.2.0 - - - attach-sources - - jar - - - - - - biz.aQute.bnd - bnd-maven-plugin - 3.5.0 - - - - bnd-process - - - - - - org.apache.maven.plugins - maven-jar-plugin - 2.6 - - - ${project.build.outputDirectory}/META-INF/MANIFEST.MF - - - - - org.apache.maven.plugins - maven-surefire-plugin - 2.22.2 - - - **/*.class - - - **/**Test.class - - - - - - org.apache.maven.plugins - maven-javadoc-plugin - 3.3.0 - - - attach-javadocs - - -Xdoclint:syntax - - - jar - - - - - - - - - AcceptanceTest - - - - org.apache.maven.plugins - maven-surefire-plugin - 2.22.2 - - - **/HttpEventCollector_*.class - - - - - - - - Unittest - - - - org.apache.maven.plugins - maven-surefire-plugin - 2.22.2 - - - **/HttpEventCollectorUnitTest.class - - - - - - - - StressTest - - - - org.apache.maven.plugins - maven-surefire-plugin - 2.22.2 - - - **/HttpLoggerStressTest.class - - - - - - - - - - - - splunk-artifactory - Splunk Releases - https://splunk.jfrog.io/splunk/ext-releases-local - - - - - splunk-artifactory - Splunk Releases - https://splunk.jfrog.io/splunk/ext-releases-local - - - - - - junit - junit - 4.13.2 - test - - - org.slf4j - slf4j-api - 1.7.30 - test - - - ch.qos.logback - logback-classic - ${logback.version} - provided - - - ch.qos.logback - logback-core - ${logback.version} - provided - - - ch.qos.logback - logback-access - ${logback.version} - provided - - - - com.squareup.okhttp3 - okhttp - 4.9.1 - - - - org.apache.logging.log4j - log4j-api - provided - ${log4j2.version} - - - - org.apache.logging.log4j - log4j-core - provided - ${log4j2.version} - - - - com.splunk - splunk - 1.6.5.0 - test - - - - com.google.code.gson - gson - 2.8.7 - - - - org.apache.commons - commons-lang3 - 3.12.0 - test - - - - - - - - org.apache.maven.plugins - maven-compiler-plugin - 3.8.1 - - 8 - 8 - - - - org.apache.maven.plugins - maven-source-plugin - 3.2.0 - - - attach-sources - - jar - - - - - - org.apache.maven.plugins - maven-javadoc-plugin - 3.3.0 - - - attach-javadocs - - jar - - - 8 - -Xdoclint:syntax - - - - - - - - - - The Apache Software License, Version 2.0 - http://www.apache.org/licenses/LICENSE-2.0.txt - repo - - - - - Splunk, Inc. - http://dev.splunk.com - - - - - Paul van Assen - source@pvanassen.nl - - - Damien Dallimore - ddallimore@splunk.com - - - Fred Ross - fross@splunk.com - - - Shakeel Mohamed - shakeel@splunk.com - - - - - scm:git:git@github.com:splunk/splunk-library-javalogging.git - scm:git:git@github.com:splunk/splunk-library-javalogging.git - HEAD - https://github.com/splunk/splunk-library-javalogging - - - - + + + 4.0.0 + + com.splunk.logging + splunk-library-javalogging + + 1.12.0-SNAPSHOT + + jar + + Splunk Logging for Java + https://dev.splunk.com/goto/sdk-slj + + + Library for structured, semantic logging of Common Information Model compliant events, meant for use with SLF4J. + + + + true + UTF-8 + + + + 2.17.0 + + + 1.2.9 + + + + Default + + true + + + + + maven-compiler-plugin + 3.8.1 + + 8 + 8 + + + + org.apache.maven.plugins + maven-source-plugin + 3.2.0 + + + attach-sources + + jar + + + + + + biz.aQute.bnd + bnd-maven-plugin + 3.5.0 + + + + bnd-process + + + + + + org.apache.maven.plugins + maven-jar-plugin + 2.6 + + + ${project.build.outputDirectory}/META-INF/MANIFEST.MF + + + + + org.apache.maven.plugins + maven-surefire-plugin + 2.22.2 + + + **/*.class + + + **/**Test.class + + + + + + org.apache.maven.plugins + maven-javadoc-plugin + 3.3.0 + + + attach-javadocs + + -Xdoclint:syntax + + + jar + + + + + + + + + AcceptanceTest + + + + org.apache.maven.plugins + maven-surefire-plugin + 2.22.2 + + + **/HttpEventCollector_*.class + + + + + + + + Unittest + + + + org.apache.maven.plugins + maven-surefire-plugin + 2.22.2 + + + **/HttpEventCollectorUnitTest.class + + + + + + + + StressTest + + + + org.apache.maven.plugins + maven-surefire-plugin + 2.22.2 + + + **/HttpLoggerStressTest.class + + + + + + + + + + + + splunk-artifactory + Splunk Releases + https://splunk.jfrog.io/splunk/ext-releases-local + + + + + splunk-artifactory + Splunk Releases + https://splunk.jfrog.io/splunk/ext-releases-local + + + + + + junit + junit + 4.13.2 + test + + + org.slf4j + slf4j-api + 1.7.30 + test + + + ch.qos.logback + logback-classic + ${logback.version} + provided + + + ch.qos.logback + logback-core + ${logback.version} + provided + + + ch.qos.logback + logback-access + ${logback.version} + provided + + + + com.squareup.okhttp3 + okhttp + 4.9.1 + + + + org.apache.logging.log4j + log4j-api + provided + ${log4j2.version} + + + + org.apache.logging.log4j + log4j-core + provided + ${log4j2.version} + + + + com.splunk + splunk + 1.6.5.0 + test + + + + com.google.code.gson + gson + 2.8.7 + + + + org.apache.commons + commons-lang3 + 3.12.0 + test + + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.8.1 + + 8 + 8 + + + + org.apache.maven.plugins + maven-source-plugin + 3.2.0 + + + attach-sources + + jar + + + + + + org.apache.maven.plugins + maven-javadoc-plugin + 3.3.0 + + + attach-javadocs + + jar + + + 8 + -Xdoclint:syntax + + + + + + org.apache.maven.plugins + maven-assembly-plugin + 3.1.1 + + + jar-with-dependencies + + + + + make-assembly + package + + single + + + + + + + + + + The Apache Software License, Version 2.0 + http://www.apache.org/licenses/LICENSE-2.0.txt + repo + + + + + Splunk, Inc. + http://dev.splunk.com + + + + + Paul van Assen + source@pvanassen.nl + + + Damien Dallimore + ddallimore@splunk.com + + + Fred Ross + fross@splunk.com + + + Shakeel Mohamed + shakeel@splunk.com + + + + + scm:git:git@github.com:splunk/splunk-library-javalogging.git + scm:git:git@github.com:splunk/splunk-library-javalogging.git + HEAD + https://github.com/splunk/splunk-library-javalogging + + + + diff --git a/src/main/java/com/splunk/logging/HttpEventCollectorJBossLoggingHandler.java b/src/main/java/com/splunk/logging/HttpEventCollectorJBossLoggingHandler.java new file mode 100644 index 00000000..b0663b17 --- /dev/null +++ b/src/main/java/com/splunk/logging/HttpEventCollectorJBossLoggingHandler.java @@ -0,0 +1,349 @@ +package com.splunk.logging; + +import java.util.HashMap; +import java.util.Locale; +import java.util.Map; +import java.util.logging.Handler; +import java.util.logging.LogRecord; + +/** + * @copyright + * + * Copyright 2013-2015 Splunk, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"): you may + * not use this file except in compliance with the License. You may obtain + * a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ + +/** + * A handler for java.util.logging that works with Splunk http event collector. + * + * details + * This is a Splunk custom java.util.logging handler that intercepts logging + * information and forwards it to a Splunk server through http event collector. + * @todo - link to http event collector documentation + * java.util.logging is configure by specifying java.util.logging.config.file + * properties file. For example: + * -Djava.util.logging.config.file=splunk-http-input.properties + * Properties file has include logging handler and its properties. + * + * # Splunk http event collector handler + * handlers = com.splunk.logging.HttpEventCollectorHandler + * + * # Http event collector application token + * com.splunk.logging.HttpEventCollectorLoggingHandler.token= + * + * # Splunk logging input url. + * com.splunk.logging.HttpEventCollectorHandler.url + * + * # Logging events metadata. + * com.splunk.logging.HttpEventCollectorLoggingHandler.index + * com.splunk.logging.HttpEventCollectorLoggingHandler.source + * com.splunk.logging.HttpEventCollectorLoggingHandler.sourcetype + * + * # Events batching parameters: + * # Delay in millisecond between sending events, by default this value is 0, i.e., and events + * # are sending immediately + * com.splunk.logging.HttpEventCollectorLoggingHandler.batch_interval + * + * # Max number of events in a batch. By default - 0, i.e., no batching + * com.splunk.logging.HttpEventCollectorLoggingHandler.batch_size_count + * + * # Max size of events in a batch. By default - 0, i.e., no batching + * com.splunk.logging.HttpEventCollectorLoggingHandler.batch_size_bytes + * + * An example of logging properties file: + * handlers = com.splunk.logging.HttpEventCollectorLoggingHandler + * com.splunk.logging.HttpEventCollectorLoggingHandler.token=81029a58-63db-4bef-9c6f-f6b7e500f098 + * + * # Splunk server + * com.splunk.logging.HttpEventCollectorLoggingHandler.url=https://localhost:8089 + * + * # Metadata + * com.splunk.logging.HttpEventCollectorLoggingHandler.index=default + * com.splunk.logging.HttpEventCollectorLoggingHandler.source=localhost + * com.splunk.logging.HttpEventCollectorLoggingHandler.sourcetype=syslog + * + * # Batching + * com.splunk.logging.HttpEventCollectorLoggingHandler.batch_interval = 500 + * com.splunk.logging.HttpEventCollectorLoggingHandler.batch_size_count = 1000 + * com.splunk.logging.HttpEventCollectorLoggingHandler.batch_size_count = 65536 + * + * # To improve system performance tracing events are sent asynchronously and + * events with the same timestamp (that has 1 millisecond resolution) may + * be indexed out of order by Splunk. send_mode parameter triggers + * "sequential mode" that guarantees preserving events order. In + * "sequential mode" performance of sending events to the server is lower. + * com.splunk.logging.HttpEventCollectorLoggingHandler.send_mode=sequential + */ + +import com.splunk.logging.hec.MetadataTags; + +/** + * An input handler for Splunk http event collector. This handler can be used by by specifying handlers = com.splunk.logging.HttpEventCollectorLoggingHandler in java.util.logging properties file. + */ +public class HttpEventCollectorJBossLoggingHandler extends Handler { + private String url; + private String token; + private String channel; + private String type; + private long delay = HttpEventCollectorSender.DefaultBatchInterval; + private long batchCount = HttpEventCollectorSender.DefaultBatchCount; + private long batchSize = HttpEventCollectorSender.DefaultBatchSize; + private long retriesOnError; + private String sendMode = "sequential"; + private String eventHeaderSerializer = ""; + private String middleware; + private String eventBodySerializer; + private String errorCallbackClass; + + private boolean includeLoggerName = true; + private boolean includeThreadName = true; + private boolean includeException = true; + + // Metadata + private String host; + private String index; + private String source; + private String sourcetype; + private String messageFormat; + + // Timeout settings + private long connectTimeout = HttpEventCollectorSender.TimeoutSettings.DEFAULT_CONNECT_TIMEOUT; + private long callTimeout = HttpEventCollectorSender.TimeoutSettings.DEFAULT_CALL_TIMEOUT; + private long readTimeout = HttpEventCollectorSender.TimeoutSettings.DEFAULT_READ_TIMEOUT; + private long writeTimeout = HttpEventCollectorSender.TimeoutSettings.DEFAULT_WRITE_TIMEOUT; + private long terminationTimeout = HttpEventCollectorSender.TimeoutSettings.DEFAULT_TERMINATION_TIMEOUT; + + private boolean disableCertificateValidation; + + private HttpEventCollectorSender sender = null; + + private void init() { + // Metadata + Map metadata = new HashMap<>(); + metadata.put(MetadataTags.HOST, host); + metadata.put(MetadataTags.INDEX, index); + metadata.put(MetadataTags.SOURCE, source); + metadata.put(MetadataTags.SOURCETYPE, sourcetype); + // Extract message format value + metadata.put(MetadataTags.MESSAGEFORMAT, messageFormat); + + // Timeout settings + HttpEventCollectorSender.TimeoutSettings timeoutSettings = new HttpEventCollectorSender.TimeoutSettings(connectTimeout, callTimeout, readTimeout, writeTimeout, terminationTimeout); + + if ("raw".equalsIgnoreCase(type)) { + if (batchCount != HttpEventCollectorSender.DefaultBatchCount || batchSize != HttpEventCollectorSender.DefaultBatchSize || delay != HttpEventCollectorSender.DefaultBatchInterval) { + throw new IllegalArgumentException("Batching configuration and sending type of raw are incompatible."); + } + batchCount = 1; + } + + // delegate all configuration params to event sender + this.sender = new HttpEventCollectorSender(url, token, channel, type, delay, batchCount, batchSize, sendMode, metadata, timeoutSettings); + + // plug a user middleware + if (middleware != null && !middleware.isEmpty()) { + try { + this.sender.addMiddleware((HttpEventCollectorMiddleware.HttpSenderMiddleware) (Class.forName(middleware).newInstance())); + } + catch (Exception ignored) { + } + } + + if (eventBodySerializer != null && !eventBodySerializer.isEmpty()) { + try { + this.sender.setEventBodySerializer((EventBodySerializer) Class.forName(eventBodySerializer).newInstance()); + } + catch (final Exception ex) { + // output error msg but not fail, it will default to use the default EventBodySerializer + System.out.println(ex); + } + } + + if (eventHeaderSerializer != null && !eventHeaderSerializer.isEmpty()) { + try { + this.sender.setEventHeaderSerializer((EventHeaderSerializer) Class.forName(eventHeaderSerializer).newInstance()); + } + catch (final Exception ex) { + // output error msg but not fail, it will default to use the default EventHeaderSerializer + System.out.println(ex); + } + } + + if (errorCallbackClass != null && !errorCallbackClass.isEmpty()) { + try { + HttpEventCollectorErrorHandler.registerClassName(errorCallbackClass); + } + catch (final Exception ex) { + // output error msg but not fail, it will default to use the default EventHeaderSerializer + System.out.println(ex); + } + } + + // plug retries middleware + if (retriesOnError > 0) { + this.sender.addMiddleware(new HttpEventCollectorResendMiddleware(retriesOnError)); + } + + if (disableCertificateValidation) { + this.sender.disableCertificateValidation(); + } + } + + /** + * java.util.logging data handler callback + * + * @param record is a logging record + */ + @Override + public void publish(LogRecord record) { + if (this.sender == null) { + init(); + } + this.sender.send(record.getMillis(), record.getLevel().toString(), getFormatter() == null ? record.getMessage() : getFormatter().format(record), + includeLoggerName ? record.getLoggerName() : null, includeThreadName ? String.format(Locale.US, "%d", record.getThreadID()) : null, null, // no property map available + (!includeException || record.getThrown() == null) ? null : record.getThrown().getMessage(), null // no marker available + ); + } + + /** + * java.util.logging data handler callback + */ + @Override + public void flush() { + this.sender.flush(); + } + + /** + * java.util.logging data handler close callback + * + * @throws SecurityException throw security exception + */ + @Override + public void close() throws SecurityException { + this.sender.close(); + } + + /**** Setters only are needed ****/ + public void setUrl(String url) { + this.url = url; + } + + public void setToken(String token) { + this.token = token; + } + + public void setChannel(String channel) { + this.channel = channel; + } + + public void setType(String type) { + this.type = type; + } + + public void setDelay(long delay) { + this.delay = delay; + } + + public void setBatchCount(long batchCount) { + this.batchCount = batchCount; + } + + public void setBatchSize(long batchSize) { + this.batchSize = batchSize; + } + + public void setRetriesOnError(long retriesOnError) { + this.retriesOnError = retriesOnError; + } + + public void setSendMode(String sendMode) { + this.sendMode = sendMode; + } + + public void setEventHeaderSerializer(String eventHeaderSerializer) { + this.eventHeaderSerializer = eventHeaderSerializer; + } + + public void setMiddleware(String middleware) { + this.middleware = middleware; + } + + public void setEventBodySerializer(String eventBodySerializer) { + this.eventBodySerializer = eventBodySerializer; + } + + public void setErrorCallbackClass(String errorCallbackClass) { + this.errorCallbackClass = errorCallbackClass; + } + + public void setIncludeLoggerName(boolean includeLoggerName) { + this.includeLoggerName = includeLoggerName; + } + + public void setIncludeThreadName(boolean includeThreadName) { + this.includeThreadName = includeThreadName; + } + + public void setIncludeException(boolean includeException) { + this.includeException = includeException; + } + + public void setHost(String host) { + this.host = host; + } + + public void setIndex(String index) { + this.index = index; + } + + public void setSource(String source) { + this.source = source; + } + + public void setSourcetype(String sourcetype) { + this.sourcetype = sourcetype; + } + + public void setMessageFormat(String messageFormat) { + this.messageFormat = messageFormat; + } + + public void setConnectTimeout(long connectTimeout) { + this.connectTimeout = connectTimeout; + } + + public void setCallTimeout(long callTimeout) { + this.callTimeout = callTimeout; + } + + public void setReadTimeout(long readTimeout) { + this.readTimeout = readTimeout; + } + + public void setWriteTimeout(long writeTimeout) { + this.writeTimeout = writeTimeout; + } + + public void setTerminationTimeout(long terminationTimeout) { + this.terminationTimeout = terminationTimeout; + } + + public void setDisableCertificateValidation(boolean disableCertificateValidation) { + this.disableCertificateValidation = disableCertificateValidation; + } + + public void setSender(HttpEventCollectorSender sender) { + this.sender = sender; + } +} diff --git a/src/main/java/com/splunk/logging/HttpEventCollectorLoggingHandler.java b/src/main/java/com/splunk/logging/HttpEventCollectorLoggingHandler.java index 7361fe10..a7743b9f 100644 --- a/src/main/java/com/splunk/logging/HttpEventCollectorLoggingHandler.java +++ b/src/main/java/com/splunk/logging/HttpEventCollectorLoggingHandler.java @@ -238,7 +238,7 @@ public void publish(LogRecord record) { this.sender.send( record.getMillis(), record.getLevel().toString(), - record.getMessage(), + getFormatter() == null ? record.getMessage() : getFormatter().format(record), includeLoggerName ? record.getLoggerName() : null, includeThreadName ? String.format(Locale.US, "%d", record.getThreadID()) : null, null, // no property map available @@ -289,4 +289,4 @@ private boolean getConfigurationBooleanProperty( return Boolean.parseBoolean( getConfigurationProperty(property, String.valueOf(defaultValue))); } -} +} \ No newline at end of file