├── .github └── dependabot.yml ├── .gitignore ├── .mvn └── wrapper │ ├── MavenWrapperDownloader.java │ └── maven-wrapper.properties ├── Jenkinsfile ├── LICENSE ├── README.md ├── mvnw ├── mvnw.cmd ├── pom.xml └── src ├── main └── java │ └── com │ └── cloudbees │ └── syslog │ ├── Facility.java │ ├── MessageFormat.java │ ├── SDElement.java │ ├── SDParam.java │ ├── Severity.java │ ├── SyslogMessage.java │ ├── integration │ └── jul │ │ ├── AbstractHandler.java │ │ ├── SyslogHandler.java │ │ ├── SyslogMessageFormatter.java │ │ └── util │ │ ├── LevelHelper.java │ │ └── LogManagerHelper.java │ ├── sender │ ├── AbstractSyslogMessageSender.java │ ├── SyslogMessageSender.java │ ├── TcpSyslogMessageSender.java │ └── UdpSyslogMessageSender.java │ └── util │ ├── CachingReference.java │ ├── ConcurrentDateFormat.java │ ├── InternalLogger.java │ └── IoUtils.java └── test └── java └── com └── cloudbees └── syslog ├── SyslogMessageTest.java ├── integration └── jul │ └── SyslogHandlerTest.java ├── sender ├── TcpSyslogMessageSenderLoadTest.java ├── TcpSyslogMessageSenderTest.java ├── UdpSyslogMessageSenderLoadTest.java └── UpdSyslogMessageSenderTest.java └── util └── CachingReferenceTest.java /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | # https://docs.github.com/en/code-security/supply-chain-security/keeping-your-dependencies-updated-automatically/configuration-options-for-dependency-updates 2 | 3 | version: 2 4 | updates: 5 | - package-ecosystem: "maven" 6 | directory: "/" 7 | schedule: 8 | interval: "weekly" 9 | - package-ecosystem: "github-actions" 10 | directory: "/" 11 | schedule: 12 | interval: "weekly" 13 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | target/ 2 | pom.xml.tag 3 | pom.xml.releaseBackup 4 | pom.xml.versionsBackup 5 | pom.xml.next 6 | release.properties 7 | dependency-reduced-pom.xml 8 | buildNumber.properties 9 | .mvn/timing.properties 10 | .mvn/wrapper/maven-wrapper.jar 11 | 12 | # IntelliJ IDEA project files 13 | *.iml 14 | *.iws 15 | *.ipr 16 | .idea 17 | 18 | # Eclipse project files 19 | .settings 20 | .classpath 21 | .project 22 | -------------------------------------------------------------------------------- /.mvn/wrapper/MavenWrapperDownloader.java: -------------------------------------------------------------------------------- 1 | /* 2 | Licensed to the Apache Software Foundation (ASF) under one 3 | or more contributor license agreements. See the NOTICE file 4 | distributed with this work for additional information 5 | regarding copyright ownership. The ASF licenses this file 6 | to you under the Apache License, Version 2.0 (the 7 | "License"); you may not use this file except in compliance 8 | with the License. You may obtain a copy of the License at 9 | 10 | http://www.apache.org/licenses/LICENSE-2.0 11 | 12 | Unless required by applicable law or agreed to in writing, 13 | software distributed under the License is distributed on an 14 | "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | KIND, either express or implied. See the License for the 16 | specific language governing permissions and limitations 17 | under the License. 18 | */ 19 | 20 | import java.net.*; 21 | import java.io.*; 22 | import java.nio.channels.*; 23 | import java.util.Properties; 24 | 25 | public class MavenWrapperDownloader { 26 | 27 | /** 28 | * Default URL to download the maven-wrapper.jar from, if no 'downloadUrl' is provided. 29 | */ 30 | private static final String DEFAULT_DOWNLOAD_URL = 31 | "https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.4.2/maven-wrapper-0.4.2.jar"; 32 | 33 | /** 34 | * Path to the maven-wrapper.properties file, which might contain a downloadUrl property to 35 | * use instead of the default one. 36 | */ 37 | private static final String MAVEN_WRAPPER_PROPERTIES_PATH = 38 | ".mvn/wrapper/maven-wrapper.properties"; 39 | 40 | /** 41 | * Path where the maven-wrapper.jar will be saved to. 42 | */ 43 | private static final String MAVEN_WRAPPER_JAR_PATH = 44 | ".mvn/wrapper/maven-wrapper.jar"; 45 | 46 | /** 47 | * Name of the property which should be used to override the default download url for the wrapper. 48 | */ 49 | private static final String PROPERTY_NAME_WRAPPER_URL = "wrapperUrl"; 50 | 51 | public static void main(String args[]) { 52 | System.out.println("- Downloader started"); 53 | File baseDirectory = new File(args[0]); 54 | System.out.println("- Using base directory: " + baseDirectory.getAbsolutePath()); 55 | 56 | // If the maven-wrapper.properties exists, read it and check if it contains a custom 57 | // wrapperUrl parameter. 58 | File mavenWrapperPropertyFile = new File(baseDirectory, MAVEN_WRAPPER_PROPERTIES_PATH); 59 | String url = DEFAULT_DOWNLOAD_URL; 60 | if(mavenWrapperPropertyFile.exists()) { 61 | FileInputStream mavenWrapperPropertyFileInputStream = null; 62 | try { 63 | mavenWrapperPropertyFileInputStream = new FileInputStream(mavenWrapperPropertyFile); 64 | Properties mavenWrapperProperties = new Properties(); 65 | mavenWrapperProperties.load(mavenWrapperPropertyFileInputStream); 66 | url = mavenWrapperProperties.getProperty(PROPERTY_NAME_WRAPPER_URL, url); 67 | } catch (IOException e) { 68 | System.out.println("- ERROR loading '" + MAVEN_WRAPPER_PROPERTIES_PATH + "'"); 69 | } finally { 70 | try { 71 | if(mavenWrapperPropertyFileInputStream != null) { 72 | mavenWrapperPropertyFileInputStream.close(); 73 | } 74 | } catch (IOException e) { 75 | // Ignore ... 76 | } 77 | } 78 | } 79 | System.out.println("- Downloading from: : " + url); 80 | 81 | File outputFile = new File(baseDirectory.getAbsolutePath(), MAVEN_WRAPPER_JAR_PATH); 82 | if(!outputFile.getParentFile().exists()) { 83 | if(!outputFile.getParentFile().mkdirs()) { 84 | System.out.println( 85 | "- ERROR creating output direcrory '" + outputFile.getParentFile().getAbsolutePath() + "'"); 86 | } 87 | } 88 | System.out.println("- Downloading to: " + outputFile.getAbsolutePath()); 89 | try { 90 | downloadFileFromURL(url, outputFile); 91 | System.out.println("Done"); 92 | System.exit(0); 93 | } catch (Throwable e) { 94 | System.out.println("- Error downloading"); 95 | e.printStackTrace(); 96 | System.exit(1); 97 | } 98 | } 99 | 100 | private static void downloadFileFromURL(String urlString, File destination) throws Exception { 101 | URL website = new URL(urlString); 102 | ReadableByteChannel rbc; 103 | rbc = Channels.newChannel(website.openStream()); 104 | FileOutputStream fos = new FileOutputStream(destination); 105 | fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE); 106 | fos.close(); 107 | rbc.close(); 108 | } 109 | 110 | } 111 | -------------------------------------------------------------------------------- /.mvn/wrapper/maven-wrapper.properties: -------------------------------------------------------------------------------- 1 | # Licensed to the Apache Software Foundation (ASF) under one 2 | # or more contributor license agreements. See the NOTICE file 3 | # distributed with this work for additional information 4 | # regarding copyright ownership. The ASF licenses this file 5 | # to you under the Apache License, Version 2.0 (the 6 | # "License"); you may not use this file except in compliance 7 | # with the License. You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, 12 | # software distributed under the License is distributed on an 13 | # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 | # KIND, either express or implied. See the License for the 15 | # specific language governing permissions and limitations 16 | # under the License. 17 | distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.8.5/apache-maven-3.8.5-bin.zip 18 | wrapperUrl=https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar 19 | -------------------------------------------------------------------------------- /Jenkinsfile: -------------------------------------------------------------------------------- 1 | /* 2 | * While this is not a plugin, it is much simpler to reuse the pipeline code for CI. This allows for 3 | * easy Linux/Windows testing and produces incrementals. The only feature that relates to plugins is 4 | * allowing one to test against multiple Jenkins versions. 5 | */ 6 | buildPlugin(useContainerAgent: true, configurations: [ 7 | [ platform: 'linux', jdk: '8' ], 8 | [ platform: 'linux', jdk: '11' ], 9 | [ platform: 'windows', jdk: '11' ] 10 | ]) 11 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2010-2013 the original author or authors 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining 4 | a copy of this software and associated documentation files (the 5 | "Software"), to deal in the Software without restriction, including 6 | without limitation the rights to use, copy, modify, merge, publish, 7 | distribute, sublicense, and/or sell copies of the Software, and to 8 | permit persons to whom the Software is furnished to do so, subject to 9 | the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be 12 | included in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 17 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 18 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 19 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 20 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Syslog Java Client 2 | 3 | ## Description 4 | 5 | Client library written in Java to send messages to a Syslog server. 6 | 7 | * `SyslogMessageSender`: send messages to a Syslog Server. Support implementations 8 | * `UdpSyslogMessageSender`: [RFC 3164 - The BSD syslog Protocol](http://tools.ietf.org/html/rfc3164) and [RFC 5426 - Transmission of Syslog Messages over UDP](http://tools.ietf.org/html/rfc5426) 9 | * `TcpSyslogMessageSender`: [RFC 6587 - Transmission of Syslog Messages over TCP](http://tools.ietf.org/html/rfc5426) (including SSL support) 10 | * `TcpSyslogMessageSender`: [RFC 5425 - Transport Layer Security (TLS) Transport Mapping for Syslog](http://tools.ietf.org/html/rfc5426) (including SSL support) 11 | * `com.cloudbees.syslog.integration.jul.SyslogHandler`: java.util.logging handler to output log messages to a Syslog server. 12 | 13 | ## Release Notes and downloads 14 | 15 | See https://github.com/CloudBees-community/syslog-java-client/releases/ 16 | 17 | ## Using the Syslog Java Client with Maven 18 | 19 | Add the following dependency in your pom.xml: 20 | 21 | ```xml 22 | 23 | com.cloudbees 24 | syslog-java-client 25 | 1.1.7 26 | 27 | ``` 28 | 29 | ## Sample UDP sender using RFC 3164 30 | 31 | ```java 32 | import com.cloudbees.syslog.Facility; 33 | import com.cloudbees.syslog.MessageFormat; 34 | import com.cloudbees.syslog.Severity; 35 | import com.cloudbees.syslog.sender.UdpSyslogMessageSender; 36 | 37 | ... 38 | 39 | // Initialise sender 40 | UdpSyslogMessageSender messageSender = new UdpSyslogMessageSender(); 41 | messageSender.setDefaultMessageHostname("myhostname"); // some syslog cloud services may use this field to transmit a secret key 42 | messageSender.setDefaultAppName("myapp"); 43 | messageSender.setDefaultFacility(Facility.USER); 44 | messageSender.setDefaultSeverity(Severity.INFORMATIONAL); 45 | messageSender.setSyslogServerHostname("127.0.0.1"); 46 | // syslog udp usually uses port 514 as per https://tools.ietf.org/html/rfc3164#page-5 47 | messageSender.setSyslogServerPort(514); 48 | messageSender.setMessageFormat(MessageFormat.RFC_3164); // optional, default is RFC 3164 49 | 50 | // send a Syslog message 51 | messageSender.sendMessage("This is a test message"); 52 | ``` 53 | 54 | ## Sample UDP sender using RFC 5424 55 | 56 | ```java 57 | import com.cloudbees.syslog.Facility; 58 | import com.cloudbees.syslog.MessageFormat; 59 | import com.cloudbees.syslog.Severity; 60 | import com.cloudbees.syslog.sender.UdpSyslogMessageSender; 61 | 62 | ... 63 | 64 | // Initialise sender 65 | UdpSyslogMessageSender messageSender = new UdpSyslogMessageSender(); 66 | messageSender.setDefaultMessageHostname("myhostname"); // some syslog cloud services may use this field to transmit a secret key 67 | messageSender.setDefaultAppName("myapp"); 68 | messageSender.setDefaultFacility(Facility.USER); 69 | messageSender.setDefaultSeverity(Severity.INFORMATIONAL); 70 | messageSender.setSyslogServerHostname("127.0.0.1"); 71 | messageSender.setSyslogServerPort(1234); 72 | messageSender.setMessageFormat(MessageFormat.RFC_5424); 73 | 74 | // send a Syslog message 75 | messageSender.sendMessage("This is a test message"); 76 | ``` 77 | 78 | ## Sample TCP sender using RFC 3164 79 | 80 | ```java 81 | import com.cloudbees.syslog.Facility; 82 | import com.cloudbees.syslog.MessageFormat; 83 | import com.cloudbees.syslog.Severity; 84 | import com.cloudbees.syslog.sender.TcpSyslogMessageSender; 85 | 86 | ... 87 | 88 | // Initialise sender 89 | TcpSyslogMessageSender messageSender = new TcpSyslogMessageSender(); 90 | messageSender.setDefaultMessageHostname("myhostname"); // some syslog cloud services may use this field to transmit a secret key 91 | messageSender.setDefaultAppName("myapp"); 92 | messageSender.setDefaultFacility(Facility.USER); 93 | messageSender.setDefaultSeverity(Severity.INFORMATIONAL); 94 | messageSender.setSyslogServerHostname("127.0.0.1"); 95 | messageSender.setSyslogServerPort(1234); 96 | messageSender.setMessageFormat(MessageFormat.RFC_3164); // optional, default is RFC 3164 97 | messageSender.setSsl(false); 98 | 99 | // send a Syslog message 100 | messageSender.sendMessage("This is a test message"); 101 | ``` 102 | 103 | ## Sample TCP over SSL sender using RFC 3164 104 | 105 | ```java 106 | import com.cloudbees.syslog.Facility; 107 | import com.cloudbees.syslog.MessageFormat; 108 | import com.cloudbees.syslog.Severity; 109 | import com.cloudbees.syslog.sender.TcpSyslogMessageSender; 110 | 111 | ... 112 | 113 | // Initialise sender 114 | TcpSyslogMessageSender messageSender = new TcpSyslogMessageSender(); 115 | messageSender.setDefaultMessageHostname("myhostname"); // some syslog cloud services may use this field to transmit a secret key 116 | messageSender.setDefaultAppName("myapp"); 117 | messageSender.setDefaultFacility(Facility.USER); 118 | messageSender.setDefaultSeverity(Severity.INFORMATIONAL); 119 | messageSender.setSyslogServerHostname("127.0.0.1"); 120 | messageSender.setSyslogServerPort(1234); 121 | messageSender.setMessageFormat(MessageFormat.RFC_3164); // optional, default is RFC 3164 122 | messageSender.setSsl(true); 123 | 124 | // send a Syslog message 125 | messageSender.sendMessage("This is a test message"); 126 | ``` 127 | 128 | ## Sample TCP over SSL sender using RFC 5425 129 | 130 | ```java 131 | import com.cloudbees.syslog.Facility; 132 | import com.cloudbees.syslog.MessageFormat; 133 | import com.cloudbees.syslog.Severity; 134 | import com.cloudbees.syslog.sender.TcpSyslogMessageSender; 135 | 136 | ... 137 | 138 | // Initialise sender 139 | TcpSyslogMessageSender messageSender = new TcpSyslogMessageSender(); 140 | messageSender.setDefaultMessageHostname("myhostname"); // some syslog cloud services may use this field to transmit a secret key 141 | messageSender.setDefaultAppName("myapp"); 142 | messageSender.setDefaultFacility(Facility.USER); 143 | messageSender.setDefaultSeverity(Severity.INFORMATIONAL); 144 | messageSender.setSyslogServerHostname("127.0.0.1"); 145 | // syslog-tls usually uses port 6514 as per https://tools.ietf.org/html/rfc5425#page-11 146 | messageSender.setSyslogServerPort(6514); 147 | messageSender.setMessageFormat(MessageFormat.RFC_5425); 148 | messageSender.setSsl(true); 149 | 150 | // send a Syslog message 151 | messageSender.sendMessage("This is a test message"); 152 | ``` 153 | -------------------------------------------------------------------------------- /mvnw: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # ---------------------------------------------------------------------------- 3 | # Licensed to the Apache Software Foundation (ASF) under one 4 | # or more contributor license agreements. See the NOTICE file 5 | # distributed with this work for additional information 6 | # regarding copyright ownership. The ASF licenses this file 7 | # to you under the Apache License, Version 2.0 (the 8 | # "License"); you may not use this file except in compliance 9 | # with the License. You may obtain a copy of the License at 10 | # 11 | # http://www.apache.org/licenses/LICENSE-2.0 12 | # 13 | # Unless required by applicable law or agreed to in writing, 14 | # software distributed under the License is distributed on an 15 | # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16 | # KIND, either express or implied. See the License for the 17 | # specific language governing permissions and limitations 18 | # under the License. 19 | # ---------------------------------------------------------------------------- 20 | 21 | # ---------------------------------------------------------------------------- 22 | # Maven Start Up Batch script 23 | # 24 | # Required ENV vars: 25 | # ------------------ 26 | # JAVA_HOME - location of a JDK home dir 27 | # 28 | # Optional ENV vars 29 | # ----------------- 30 | # M2_HOME - location of maven2's installed home dir 31 | # MAVEN_OPTS - parameters passed to the Java VM when running Maven 32 | # e.g. to debug Maven itself, use 33 | # set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 34 | # MAVEN_SKIP_RC - flag to disable loading of mavenrc files 35 | # ---------------------------------------------------------------------------- 36 | 37 | if [ -z "$MAVEN_SKIP_RC" ] ; then 38 | 39 | if [ -f /usr/local/etc/mavenrc ] ; then 40 | . /usr/local/etc/mavenrc 41 | fi 42 | 43 | if [ -f /etc/mavenrc ] ; then 44 | . /etc/mavenrc 45 | fi 46 | 47 | if [ -f "$HOME/.mavenrc" ] ; then 48 | . "$HOME/.mavenrc" 49 | fi 50 | 51 | fi 52 | 53 | # OS specific support. $var _must_ be set to either true or false. 54 | cygwin=false; 55 | darwin=false; 56 | mingw=false 57 | case "`uname`" in 58 | CYGWIN*) cygwin=true ;; 59 | MINGW*) mingw=true;; 60 | Darwin*) darwin=true 61 | # Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home 62 | # See https://developer.apple.com/library/mac/qa/qa1170/_index.html 63 | if [ -z "$JAVA_HOME" ]; then 64 | if [ -x "/usr/libexec/java_home" ]; then 65 | export JAVA_HOME="`/usr/libexec/java_home`" 66 | else 67 | export JAVA_HOME="/Library/Java/Home" 68 | fi 69 | fi 70 | ;; 71 | esac 72 | 73 | if [ -z "$JAVA_HOME" ] ; then 74 | if [ -r /etc/gentoo-release ] ; then 75 | JAVA_HOME=`java-config --jre-home` 76 | fi 77 | fi 78 | 79 | if [ -z "$M2_HOME" ] ; then 80 | ## resolve links - $0 may be a link to maven's home 81 | PRG="$0" 82 | 83 | # need this for relative symlinks 84 | while [ -h "$PRG" ] ; do 85 | ls=`ls -ld "$PRG"` 86 | link=`expr "$ls" : '.*-> \(.*\)$'` 87 | if expr "$link" : '/.*' > /dev/null; then 88 | PRG="$link" 89 | else 90 | PRG="`dirname "$PRG"`/$link" 91 | fi 92 | done 93 | 94 | saveddir=`pwd` 95 | 96 | M2_HOME=`dirname "$PRG"`/.. 97 | 98 | # make it fully qualified 99 | M2_HOME=`cd "$M2_HOME" && pwd` 100 | 101 | cd "$saveddir" 102 | # echo Using m2 at $M2_HOME 103 | fi 104 | 105 | # For Cygwin, ensure paths are in UNIX format before anything is touched 106 | if $cygwin ; then 107 | [ -n "$M2_HOME" ] && 108 | M2_HOME=`cygpath --unix "$M2_HOME"` 109 | [ -n "$JAVA_HOME" ] && 110 | JAVA_HOME=`cygpath --unix "$JAVA_HOME"` 111 | [ -n "$CLASSPATH" ] && 112 | CLASSPATH=`cygpath --path --unix "$CLASSPATH"` 113 | fi 114 | 115 | # For Mingw, ensure paths are in UNIX format before anything is touched 116 | if $mingw ; then 117 | [ -n "$M2_HOME" ] && 118 | M2_HOME="`(cd "$M2_HOME"; pwd)`" 119 | [ -n "$JAVA_HOME" ] && 120 | JAVA_HOME="`(cd "$JAVA_HOME"; pwd)`" 121 | fi 122 | 123 | if [ -z "$JAVA_HOME" ]; then 124 | javaExecutable="`which javac`" 125 | if [ -n "$javaExecutable" ] && ! [ "`expr \"$javaExecutable\" : '\([^ ]*\)'`" = "no" ]; then 126 | # readlink(1) is not available as standard on Solaris 10. 127 | readLink=`which readlink` 128 | if [ ! `expr "$readLink" : '\([^ ]*\)'` = "no" ]; then 129 | if $darwin ; then 130 | javaHome="`dirname \"$javaExecutable\"`" 131 | javaExecutable="`cd \"$javaHome\" && pwd -P`/javac" 132 | else 133 | javaExecutable="`readlink -f \"$javaExecutable\"`" 134 | fi 135 | javaHome="`dirname \"$javaExecutable\"`" 136 | javaHome=`expr "$javaHome" : '\(.*\)/bin'` 137 | JAVA_HOME="$javaHome" 138 | export JAVA_HOME 139 | fi 140 | fi 141 | fi 142 | 143 | if [ -z "$JAVACMD" ] ; then 144 | if [ -n "$JAVA_HOME" ] ; then 145 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 146 | # IBM's JDK on AIX uses strange locations for the executables 147 | JAVACMD="$JAVA_HOME/jre/sh/java" 148 | else 149 | JAVACMD="$JAVA_HOME/bin/java" 150 | fi 151 | else 152 | JAVACMD="`\\unset -f command; \\command -v java`" 153 | fi 154 | fi 155 | 156 | if [ ! -x "$JAVACMD" ] ; then 157 | echo "Error: JAVA_HOME is not defined correctly." >&2 158 | echo " We cannot execute $JAVACMD" >&2 159 | exit 1 160 | fi 161 | 162 | if [ -z "$JAVA_HOME" ] ; then 163 | echo "Warning: JAVA_HOME environment variable is not set." 164 | fi 165 | 166 | CLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher 167 | 168 | # traverses directory structure from process work directory to filesystem root 169 | # first directory with .mvn subdirectory is considered project base directory 170 | find_maven_basedir() { 171 | 172 | if [ -z "$1" ] 173 | then 174 | echo "Path not specified to find_maven_basedir" 175 | return 1 176 | fi 177 | 178 | basedir="$1" 179 | wdir="$1" 180 | while [ "$wdir" != '/' ] ; do 181 | if [ -d "$wdir"/.mvn ] ; then 182 | basedir=$wdir 183 | break 184 | fi 185 | # workaround for JBEAP-8937 (on Solaris 10/Sparc) 186 | if [ -d "${wdir}" ]; then 187 | wdir=`cd "$wdir/.."; pwd` 188 | fi 189 | # end of workaround 190 | done 191 | echo "${basedir}" 192 | } 193 | 194 | # concatenates all lines of a file 195 | concat_lines() { 196 | if [ -f "$1" ]; then 197 | echo "$(tr -s '\n' ' ' < "$1")" 198 | fi 199 | } 200 | 201 | BASE_DIR=`find_maven_basedir "$(pwd)"` 202 | if [ -z "$BASE_DIR" ]; then 203 | exit 1; 204 | fi 205 | 206 | ########################################################################################## 207 | # Extension to allow automatically downloading the maven-wrapper.jar from Maven-central 208 | # This allows using the maven wrapper in projects that prohibit checking in binary data. 209 | ########################################################################################## 210 | if [ -r "$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" ]; then 211 | if [ "$MVNW_VERBOSE" = true ]; then 212 | echo "Found .mvn/wrapper/maven-wrapper.jar" 213 | fi 214 | else 215 | if [ "$MVNW_VERBOSE" = true ]; then 216 | echo "Couldn't find .mvn/wrapper/maven-wrapper.jar, downloading it ..." 217 | fi 218 | if [ -n "$MVNW_REPOURL" ]; then 219 | jarUrl="$MVNW_REPOURL/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar" 220 | else 221 | jarUrl="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar" 222 | fi 223 | while IFS="=" read key value; do 224 | case "$key" in (wrapperUrl) jarUrl="$value"; break ;; 225 | esac 226 | done < "$BASE_DIR/.mvn/wrapper/maven-wrapper.properties" 227 | if [ "$MVNW_VERBOSE" = true ]; then 228 | echo "Downloading from: $jarUrl" 229 | fi 230 | wrapperJarPath="$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" 231 | if $cygwin; then 232 | wrapperJarPath=`cygpath --path --windows "$wrapperJarPath"` 233 | fi 234 | 235 | if command -v wget > /dev/null; then 236 | if [ "$MVNW_VERBOSE" = true ]; then 237 | echo "Found wget ... using wget" 238 | fi 239 | if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then 240 | wget "$jarUrl" -O "$wrapperJarPath" || rm -f "$wrapperJarPath" 241 | else 242 | wget --http-user=$MVNW_USERNAME --http-password=$MVNW_PASSWORD "$jarUrl" -O "$wrapperJarPath" || rm -f "$wrapperJarPath" 243 | fi 244 | elif command -v curl > /dev/null; then 245 | if [ "$MVNW_VERBOSE" = true ]; then 246 | echo "Found curl ... using curl" 247 | fi 248 | if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then 249 | curl -o "$wrapperJarPath" "$jarUrl" -f 250 | else 251 | curl --user $MVNW_USERNAME:$MVNW_PASSWORD -o "$wrapperJarPath" "$jarUrl" -f 252 | fi 253 | 254 | else 255 | if [ "$MVNW_VERBOSE" = true ]; then 256 | echo "Falling back to using Java to download" 257 | fi 258 | javaClass="$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.java" 259 | # For Cygwin, switch paths to Windows format before running javac 260 | if $cygwin; then 261 | javaClass=`cygpath --path --windows "$javaClass"` 262 | fi 263 | if [ -e "$javaClass" ]; then 264 | if [ ! -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then 265 | if [ "$MVNW_VERBOSE" = true ]; then 266 | echo " - Compiling MavenWrapperDownloader.java ..." 267 | fi 268 | # Compiling the Java class 269 | ("$JAVA_HOME/bin/javac" "$javaClass") 270 | fi 271 | if [ -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then 272 | # Running the downloader 273 | if [ "$MVNW_VERBOSE" = true ]; then 274 | echo " - Running MavenWrapperDownloader.java ..." 275 | fi 276 | ("$JAVA_HOME/bin/java" -cp .mvn/wrapper MavenWrapperDownloader "$MAVEN_PROJECTBASEDIR") 277 | fi 278 | fi 279 | fi 280 | fi 281 | ########################################################################################## 282 | # End of extension 283 | ########################################################################################## 284 | 285 | export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"} 286 | if [ "$MVNW_VERBOSE" = true ]; then 287 | echo $MAVEN_PROJECTBASEDIR 288 | fi 289 | MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS" 290 | 291 | # For Cygwin, switch paths to Windows format before running java 292 | if $cygwin; then 293 | [ -n "$M2_HOME" ] && 294 | M2_HOME=`cygpath --path --windows "$M2_HOME"` 295 | [ -n "$JAVA_HOME" ] && 296 | JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"` 297 | [ -n "$CLASSPATH" ] && 298 | CLASSPATH=`cygpath --path --windows "$CLASSPATH"` 299 | [ -n "$MAVEN_PROJECTBASEDIR" ] && 300 | MAVEN_PROJECTBASEDIR=`cygpath --path --windows "$MAVEN_PROJECTBASEDIR"` 301 | fi 302 | 303 | # Provide a "standardized" way to retrieve the CLI args that will 304 | # work with both Windows and non-Windows executions. 305 | MAVEN_CMD_LINE_ARGS="$MAVEN_CONFIG $@" 306 | export MAVEN_CMD_LINE_ARGS 307 | 308 | WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain 309 | 310 | exec "$JAVACMD" \ 311 | $MAVEN_OPTS \ 312 | $MAVEN_DEBUG_OPTS \ 313 | -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \ 314 | "-Dmaven.home=${M2_HOME}" \ 315 | "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \ 316 | ${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@" 317 | -------------------------------------------------------------------------------- /mvnw.cmd: -------------------------------------------------------------------------------- 1 | @REM ---------------------------------------------------------------------------- 2 | @REM Licensed to the Apache Software Foundation (ASF) under one 3 | @REM or more contributor license agreements. See the NOTICE file 4 | @REM distributed with this work for additional information 5 | @REM regarding copyright ownership. The ASF licenses this file 6 | @REM to you under the Apache License, Version 2.0 (the 7 | @REM "License"); you may not use this file except in compliance 8 | @REM with the License. You may obtain a copy of the License at 9 | @REM 10 | @REM http://www.apache.org/licenses/LICENSE-2.0 11 | @REM 12 | @REM Unless required by applicable law or agreed to in writing, 13 | @REM software distributed under the License is distributed on an 14 | @REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | @REM KIND, either express or implied. See the License for the 16 | @REM specific language governing permissions and limitations 17 | @REM under the License. 18 | @REM ---------------------------------------------------------------------------- 19 | 20 | @REM ---------------------------------------------------------------------------- 21 | @REM Maven Start Up Batch script 22 | @REM 23 | @REM Required ENV vars: 24 | @REM JAVA_HOME - location of a JDK home dir 25 | @REM 26 | @REM Optional ENV vars 27 | @REM M2_HOME - location of maven2's installed home dir 28 | @REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands 29 | @REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a keystroke before ending 30 | @REM MAVEN_OPTS - parameters passed to the Java VM when running Maven 31 | @REM e.g. to debug Maven itself, use 32 | @REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 33 | @REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files 34 | @REM ---------------------------------------------------------------------------- 35 | 36 | @REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on' 37 | @echo off 38 | @REM set title of command window 39 | title %0 40 | @REM enable echoing by setting MAVEN_BATCH_ECHO to 'on' 41 | @if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO% 42 | 43 | @REM set %HOME% to equivalent of $HOME 44 | if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%") 45 | 46 | @REM Execute a user defined script before this one 47 | if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre 48 | @REM check for pre script, once with legacy .bat ending and once with .cmd ending 49 | if exist "%USERPROFILE%\mavenrc_pre.bat" call "%USERPROFILE%\mavenrc_pre.bat" %* 50 | if exist "%USERPROFILE%\mavenrc_pre.cmd" call "%USERPROFILE%\mavenrc_pre.cmd" %* 51 | :skipRcPre 52 | 53 | @setlocal 54 | 55 | set ERROR_CODE=0 56 | 57 | @REM To isolate internal variables from possible post scripts, we use another setlocal 58 | @setlocal 59 | 60 | @REM ==== START VALIDATION ==== 61 | if not "%JAVA_HOME%" == "" goto OkJHome 62 | 63 | echo. 64 | echo Error: JAVA_HOME not found in your environment. >&2 65 | echo Please set the JAVA_HOME variable in your environment to match the >&2 66 | echo location of your Java installation. >&2 67 | echo. 68 | goto error 69 | 70 | :OkJHome 71 | if exist "%JAVA_HOME%\bin\java.exe" goto init 72 | 73 | echo. 74 | echo Error: JAVA_HOME is set to an invalid directory. >&2 75 | echo JAVA_HOME = "%JAVA_HOME%" >&2 76 | echo Please set the JAVA_HOME variable in your environment to match the >&2 77 | echo location of your Java installation. >&2 78 | echo. 79 | goto error 80 | 81 | @REM ==== END VALIDATION ==== 82 | 83 | :init 84 | 85 | @REM Find the project base dir, i.e. the directory that contains the folder ".mvn". 86 | @REM Fallback to current working directory if not found. 87 | 88 | set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR% 89 | IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir 90 | 91 | set EXEC_DIR=%CD% 92 | set WDIR=%EXEC_DIR% 93 | :findBaseDir 94 | IF EXIST "%WDIR%"\.mvn goto baseDirFound 95 | cd .. 96 | IF "%WDIR%"=="%CD%" goto baseDirNotFound 97 | set WDIR=%CD% 98 | goto findBaseDir 99 | 100 | :baseDirFound 101 | set MAVEN_PROJECTBASEDIR=%WDIR% 102 | cd "%EXEC_DIR%" 103 | goto endDetectBaseDir 104 | 105 | :baseDirNotFound 106 | set MAVEN_PROJECTBASEDIR=%EXEC_DIR% 107 | cd "%EXEC_DIR%" 108 | 109 | :endDetectBaseDir 110 | 111 | IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig 112 | 113 | @setlocal EnableExtensions EnableDelayedExpansion 114 | for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a 115 | @endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS% 116 | 117 | :endReadAdditionalConfig 118 | 119 | SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe" 120 | set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar" 121 | set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain 122 | 123 | set DOWNLOAD_URL="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar" 124 | 125 | FOR /F "usebackq tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO ( 126 | IF "%%A"=="wrapperUrl" SET DOWNLOAD_URL=%%B 127 | ) 128 | 129 | @REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central 130 | @REM This allows using the maven wrapper in projects that prohibit checking in binary data. 131 | if exist %WRAPPER_JAR% ( 132 | if "%MVNW_VERBOSE%" == "true" ( 133 | echo Found %WRAPPER_JAR% 134 | ) 135 | ) else ( 136 | if not "%MVNW_REPOURL%" == "" ( 137 | SET DOWNLOAD_URL="%MVNW_REPOURL%/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar" 138 | ) 139 | if "%MVNW_VERBOSE%" == "true" ( 140 | echo Couldn't find %WRAPPER_JAR%, downloading it ... 141 | echo Downloading from: %DOWNLOAD_URL% 142 | ) 143 | 144 | powershell -Command "&{"^ 145 | "$webclient = new-object System.Net.WebClient;"^ 146 | "if (-not ([string]::IsNullOrEmpty('%MVNW_USERNAME%') -and [string]::IsNullOrEmpty('%MVNW_PASSWORD%'))) {"^ 147 | "$webclient.Credentials = new-object System.Net.NetworkCredential('%MVNW_USERNAME%', '%MVNW_PASSWORD%');"^ 148 | "}"^ 149 | "[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; $webclient.DownloadFile('%DOWNLOAD_URL%', '%WRAPPER_JAR%')"^ 150 | "}" 151 | if "%MVNW_VERBOSE%" == "true" ( 152 | echo Finished downloading %WRAPPER_JAR% 153 | ) 154 | ) 155 | @REM End of extension 156 | 157 | @REM Provide a "standardized" way to retrieve the CLI args that will 158 | @REM work with both Windows and non-Windows executions. 159 | set MAVEN_CMD_LINE_ARGS=%* 160 | 161 | %MAVEN_JAVA_EXE% ^ 162 | %JVM_CONFIG_MAVEN_PROPS% ^ 163 | %MAVEN_OPTS% ^ 164 | %MAVEN_DEBUG_OPTS% ^ 165 | -classpath %WRAPPER_JAR% ^ 166 | "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" ^ 167 | %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %* 168 | if ERRORLEVEL 1 goto error 169 | goto end 170 | 171 | :error 172 | set ERROR_CODE=1 173 | 174 | :end 175 | @endlocal & set ERROR_CODE=%ERROR_CODE% 176 | 177 | if not "%MAVEN_SKIP_RC%"=="" goto skipRcPost 178 | @REM check for post script, once with legacy .bat ending and once with .cmd ending 179 | if exist "%USERPROFILE%\mavenrc_post.bat" call "%USERPROFILE%\mavenrc_post.bat" 180 | if exist "%USERPROFILE%\mavenrc_post.cmd" call "%USERPROFILE%\mavenrc_post.cmd" 181 | :skipRcPost 182 | 183 | @REM pause the script if MAVEN_BATCH_PAUSE is set to 'on' 184 | if "%MAVEN_BATCH_PAUSE%"=="on" pause 185 | 186 | if "%MAVEN_TERMINATE_CMD%"=="on" exit %ERROR_CODE% 187 | 188 | cmd /C exit /B %ERROR_CODE% 189 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 17 | 18 | 4.0.0 19 | 20 | com.cloudbees 21 | syslog-java-client 22 | 1.1.8-SNAPSHOT 23 | bundle 24 | 25 | syslog-java-client 26 | Syslog Java Client 27 | https://github.com/jenkinsci/syslog-java-client/ 28 | 2014 29 | 30 | 31 | The Apache Software License, Version 2.0 32 | http://www.apache.org/licenses/LICENSE-2.0.txt 33 | repo 34 | 35 | 36 | 37 | 38 | 39 | Cyrille Le Clerc 40 | cleclerc@cloudbees.com 41 | 42 | 43 | 44 | 45 | scm:git:git://github.com/jenkinsci/syslog-java-client.git 46 | scm:git:git@github.com:jenkinsci/syslog-java-client.git 47 | HEAD 48 | https://github.com/jenkinsci/syslog-java-client/ 49 | 50 | 51 | 52 | UTF-8 53 | UTF-8 54 | UTF-8 55 | 56 | 57 | 58 | 59 | com.github.spotbugs 60 | spotbugs-annotations 61 | 4.8.6 62 | true 63 | 64 | 65 | com.google.code.findbugs 66 | jsr305 67 | 68 | 69 | 70 | 71 | net.jcip 72 | jcip-annotations 73 | 1.0 74 | true 75 | 76 | 77 | junit 78 | junit 79 | 4.13.2 80 | test 81 | 82 | 83 | org.hamcrest 84 | hamcrest 85 | 3.0 86 | test 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | org.apache.maven.plugins 95 | maven-compiler-plugin 96 | 3.14.0 97 | 98 | 99 | org.apache.maven.plugins 100 | maven-javadoc-plugin 101 | 3.11.2 102 | 103 | 104 | org.apache.maven.plugins 105 | maven-source-plugin 106 | 3.3.1 107 | 108 | 109 | org.apache.maven.plugins 110 | maven-surefire-plugin 111 | 3.5.3 112 | 113 | 114 | 115 | 116 | 117 | com.github.spotbugs 118 | spotbugs-maven-plugin 119 | 4.8.6.6 120 | 121 | High 122 | 123 | 124 | 125 | spotbugs 126 | 127 | check 128 | 129 | verify 130 | 131 | 132 | 133 | 134 | org.apache.felix 135 | maven-bundle-plugin 136 | 5.1.9 137 | true 138 | 139 | 140 | maven-enforcer-plugin 141 | 3.5.0 142 | 143 | 144 | display-info 145 | 146 | display-info 147 | enforce 148 | 149 | validate 150 | 151 | 152 | 153 | [3.8.1,) 154 | 3.8.1 required to no longer download dependencies via HTTP (use HTTPS instead). 155 | 156 | 157 | [1.8.0,] 158 | 159 | 160 | 161 | 162 | org.apache.logging.log4j:*:(,2.15.0-rc1] 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | org.apache.maven.plugins 172 | maven-javadoc-plugin 173 | 174 | all,-missing,-reference 175 | en_US 176 | 177 | 178 | 179 | org.apache.maven.plugins 180 | maven-release-plugin 181 | 3.1.1 182 | 183 | false 184 | jenkins-release 185 | 186 | 187 | 188 | org.sonatype.plugins 189 | nexus-staging-maven-plugin 190 | 1.7.0 191 | true 192 | 193 | sonatype-nexus-staging 194 | https://oss.sonatype.org/ 195 | true 196 | 197 | 198 | 199 | 200 | 201 | 202 | jdk-8-and-below 203 | 204 | (,1.8] 205 | 206 | 207 | 208 | 209 | maven-compiler-plugin 210 | 211 | 1.8 212 | 1.8 213 | 1.8 214 | 1.8 215 | 216 | 217 | 218 | maven-javadoc-plugin 219 | 220 | 1.8 221 | 222 | 223 | 224 | 225 | 226 | 227 | jdk-9-and-above 228 | 229 | [9,) 230 | 231 | 232 | 233 | 234 | maven-compiler-plugin 235 | 236 | 8 237 | 8 238 | 239 | 240 | 241 | maven-javadoc-plugin 242 | 243 | 8 244 | 245 | 246 | 247 | 248 | 249 | 250 | jenkins-release 251 | 252 | 253 | 254 | org.apache.maven.plugins 255 | maven-gpg-plugin 256 | 3.2.7 257 | 258 | 259 | sign-artifacts 260 | 261 | sign 262 | 263 | verify 264 | 265 | 266 | 267 | 268 | org.apache.maven.plugins 269 | maven-javadoc-plugin 270 | 271 | 272 | attach-javadocs 273 | 274 | jar 275 | 276 | 277 | 278 | 279 | 280 | org.apache.maven.plugins 281 | maven-source-plugin 282 | 283 | 284 | attach-sources 285 | 286 | jar-no-fork 287 | 288 | 289 | 290 | 291 | 292 | 293 | 294 | 295 | network-constrained 296 | 297 | 298 | env.CI 299 | 300 | 301 | 302 | 303 | 304 | org.apache.maven.plugins 305 | maven-surefire-plugin 306 | 307 | 308 | com.cloudbees.syslog.sender.TcpSyslogMessageSenderTest 309 | 310 | 311 | 312 | 313 | 314 | 315 | 316 | 317 | -------------------------------------------------------------------------------- /src/main/java/com/cloudbees/syslog/Facility.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2010-2014, CloudBees Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.cloudbees.syslog; 17 | 18 | import edu.umd.cs.findbugs.annotations.NonNull; 19 | import edu.umd.cs.findbugs.annotations.Nullable; 20 | import java.util.Comparator; 21 | import java.util.HashMap; 22 | import java.util.Map; 23 | 24 | /** 25 | * Syslog facility as defined in RFC 5424 - The Syslog Protocol. 26 | * 27 | * See RFC 5427 - Textual Conventions for Syslog Management for the {@link #label}. 28 | * 29 | * @author Cyrille Le Clerc 30 | */ 31 | public enum Facility implements Comparable { 32 | 33 | /** 34 | * kernel messages, numerical code 0. 35 | */ 36 | KERN(0, "KERN"), 37 | /** 38 | * user-level messages, numerical code 1. 39 | */ 40 | USER(1, "USER"), 41 | /** 42 | * mail system, numerical code 2. 43 | */ 44 | MAIL(2, "MAIL"), 45 | /** 46 | * system daemons, numerical code 3. 47 | */ 48 | DAEMON(3, "DAEMON"), 49 | /** 50 | * security/authorization messages, numerical code 4. 51 | */ 52 | AUTH(4, "AUTH"), 53 | /** 54 | * messages generated internally by syslogd, numerical code 5. 55 | */ 56 | SYSLOG(5, "SYSLOG"), 57 | /** 58 | * line printer subsystem, numerical code 6. 59 | */ 60 | LPR(6, "LPR"), 61 | /** 62 | * network news subsystem, numerical code 7. 63 | */ 64 | NEWS(7, "NEWS"), 65 | /** 66 | * UUCP subsystem, numerical code 8 67 | */ 68 | UUCP(8, "UUCP"), 69 | /** 70 | * clock daemon, numerical code 9. 71 | */ 72 | CRON(9, "CRON"), 73 | /** 74 | * security/authorization messages, numerical code 10. 75 | */ 76 | AUTHPRIV(10, "AUTHPRIV"), 77 | /** 78 | * ftp daemon, numerical code 11. 79 | */ 80 | FTP(11, "FTP"), 81 | /** 82 | * NTP subsystem, numerical code 12. 83 | */ 84 | NTP(12, "NTP"), 85 | /** 86 | * log audit, numerical code 13. 87 | */ 88 | AUDIT(13, "AUDIT"), 89 | /** 90 | * log alert, numerical code 14. 91 | */ 92 | ALERT(14, "ALERT"), 93 | /** 94 | * clock daemon, numerical code 15. 95 | */ 96 | CLOCK(15, "CLOCK"), 97 | /** 98 | * reserved for local use, numerical code 16. 99 | */ 100 | LOCAL0(16, "LOCAL0"), 101 | /** 102 | * reserved for local use, numerical code 17. 103 | */ 104 | LOCAL1(17, "LOCAL1"), 105 | /** 106 | * reserved for local use, numerical code 18. 107 | */ 108 | LOCAL2(18, "LOCAL2"), 109 | /** 110 | * reserved for local use, numerical code 19. 111 | */ 112 | LOCAL3(19, "LOCAL3"), 113 | /** 114 | * reserved for local use, numerical code 20. 115 | */ 116 | LOCAL4(20, "LOCAL4"), 117 | /** 118 | * reserved for local use, numerical code 21. 119 | */ 120 | LOCAL5(21, "LOCAL5"), 121 | /** 122 | * reserved for local use, numerical code 22. 123 | */ 124 | LOCAL6(22, "LOCAL6"), 125 | /** 126 | * reserved for local use, numerical code 23. 127 | */ 128 | LOCAL7(23, "LOCAL7"); 129 | 130 | // mapping 131 | private final static Map facilityFromLabel = new HashMap<>(); 132 | private final static Map facilityFromNumericalCode = new HashMap<>(); 133 | 134 | static { 135 | for (Facility facility : Facility.values()) { 136 | facilityFromLabel.put(facility.label, facility); 137 | facilityFromNumericalCode.put(facility.numericalCode, facility); 138 | } 139 | } 140 | 141 | /** 142 | * Syslog facility numerical code 143 | */ 144 | private final int numericalCode; 145 | /** 146 | * Syslog facility textual code. Not {@code null} 147 | */ 148 | @NonNull 149 | private final String label; 150 | 151 | Facility(int numericalCode, @NonNull String label) { 152 | this.numericalCode = numericalCode; 153 | this.label = label; 154 | } 155 | 156 | /** 157 | * @param numericalCode Syslog facility numerical code 158 | * @return Syslog facility, not {@code null} 159 | * @throws IllegalArgumentException the given numericalCode is not a valid Syslog facility numerical code 160 | */ 161 | @NonNull 162 | public static Facility fromNumericalCode(int numericalCode) throws IllegalArgumentException { 163 | Facility facility = facilityFromNumericalCode.get(numericalCode); 164 | if (facility == null) { 165 | throw new IllegalArgumentException("Invalid facility '" + numericalCode + "'"); 166 | } 167 | return facility; 168 | } 169 | 170 | /** 171 | * @param label Syslog facility textual code. {@code null} or empty returns {@code null} 172 | * @return Syslog facility, {@code null} if given value is {@code null} 173 | * @throws IllegalArgumentException the given value is not a valid Syslog facility textual code 174 | */ 175 | @Nullable 176 | public static Facility fromLabel(String label) throws IllegalArgumentException { 177 | if (label == null || label.isEmpty()) 178 | return null; 179 | 180 | Facility facility = facilityFromLabel.get(label); 181 | if (facility == null) { 182 | throw new IllegalArgumentException("Invalid facility '" + label + "'"); 183 | } 184 | return facility; 185 | } 186 | 187 | /** 188 | * Syslog facility numerical code 189 | */ 190 | public int numericalCode() { 191 | return numericalCode; 192 | } 193 | 194 | /** 195 | * Syslog facility textual code. Not {@code null}. 196 | */ 197 | public String label() { 198 | return label; 199 | } 200 | 201 | /** 202 | * Compare on {@link Facility#numericalCode()} 203 | */ 204 | public static Comparator comparator() { 205 | return Comparator.comparingInt(f -> f.numericalCode); 206 | } 207 | } 208 | -------------------------------------------------------------------------------- /src/main/java/com/cloudbees/syslog/MessageFormat.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2010-2014, CloudBees Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.cloudbees.syslog; 17 | 18 | /** 19 | * Format of the Syslog message. 20 | * 21 | * @author Cyrille Le Clerc 22 | */ 23 | public enum MessageFormat { 24 | /** 25 | * RFC 3614 - BSD syslog Protocol 26 | */ 27 | RFC_3164, 28 | /** 29 | * RFC 5424 - The Syslog Protocol 30 | */ 31 | RFC_5424, 32 | /** 33 | * RFC 5425 - Transport Layer Security (TLS) Transport Mapping for Syslog 34 | */ 35 | RFC_5425 36 | } 37 | -------------------------------------------------------------------------------- /src/main/java/com/cloudbees/syslog/SDElement.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2010-2014, CloudBees Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.cloudbees.syslog; 17 | 18 | import java.io.Serializable; 19 | import java.util.ArrayList; 20 | import java.util.Arrays; 21 | import java.util.Collections; 22 | import java.util.List; 23 | import java.util.Objects; 24 | 25 | /** 26 | * A SD-ELEMENT 27 | * 28 | * @author Brett Bergquist 29 | */ 30 | public class SDElement implements Serializable { 31 | 32 | private static final long serialVersionUID = 1L; 33 | 34 | /** 35 | * Reserved SD-IDs as documented in RFC-5424 36 | */ 37 | private final List RESERVED_SDID = Collections.unmodifiableList(Arrays.asList("timeQuality", "origin", "meta")); 38 | 39 | public SDElement(String sdID) { 40 | validateSDID(sdID); 41 | this.sdID = sdID; 42 | } 43 | 44 | public SDElement(String sdID, SDParam... sdParams) { 45 | validateSDID(sdID); 46 | this.sdID = sdID; 47 | this.sdParams.addAll(Arrays.asList(sdParams)); 48 | } 49 | 50 | private String sdID; 51 | 52 | /** 53 | * Get the value of sdID 54 | * 55 | * @return the value of sdID 56 | */ 57 | public String getSdID() { 58 | return sdID; 59 | } 60 | 61 | private List sdParams = new ArrayList<>(); 62 | 63 | /** 64 | * Get the value of sdParams 65 | * 66 | * @return the value of sdParams 67 | */ 68 | public List getSdParams() { 69 | return sdParams; 70 | } 71 | 72 | /** 73 | * Set the value of sdParams 74 | * 75 | * @param sdParams new value of sdParams 76 | */ 77 | public void setSdParams(List sdParams) { 78 | if (null == sdParams) { 79 | throw new IllegalArgumentException("sdParams list cannot be null"); 80 | } 81 | this.sdParams.addAll(sdParams); 82 | } 83 | 84 | /** 85 | * Adds a SDParam 86 | * @param paramName the PARAM-NAME 87 | * @param paramValue the PARAM-VALUE 88 | * @return 89 | */ 90 | public SDElement addSDParam(String paramName, String paramValue) { 91 | return addSDParam(new SDParam(paramName, paramValue)); 92 | } 93 | 94 | public SDElement addSDParam(SDParam sdParam) { 95 | this.sdParams.add(sdParam); 96 | return this; 97 | } 98 | 99 | @Override 100 | public int hashCode() { 101 | int hash = 7; 102 | hash = 97 * hash + Objects.hashCode(this.sdID); 103 | return hash; 104 | } 105 | 106 | @Override 107 | public boolean equals(Object obj) { 108 | if (this == obj) { 109 | return true; 110 | } 111 | if (obj == null) { 112 | return false; 113 | } 114 | if (getClass() != obj.getClass()) { 115 | return false; 116 | } 117 | final SDElement other = (SDElement) obj; 118 | return Objects.equals(this.sdID, other.sdID); 119 | } 120 | 121 | private void validateSDID(String sdName) { 122 | if (null == sdName) { 123 | throw new IllegalArgumentException("SD-ID cannot be null"); 124 | } 125 | if (sdName.length() > 32) { 126 | throw new IllegalArgumentException("SD-ID must be less than 32 characters: " + sdName); 127 | } 128 | if (sdName.contains("=")) { 129 | throw new IllegalArgumentException("SD-ID cannot contain '='"); 130 | } 131 | if (sdName.contains(" ")) { 132 | throw new IllegalArgumentException("SD-ID cannot contain ' '"); 133 | } 134 | if (sdName.contains("]")) { 135 | throw new IllegalArgumentException("SD-ID cannot contain ']'"); 136 | } 137 | if (sdName.contains("\"")) { 138 | throw new IllegalArgumentException("SD-ID cannot contain '\"'"); 139 | } 140 | if (! sdName.contains("@")) { 141 | boolean found = false; 142 | for (String rn : RESERVED_SDID) { 143 | if (rn.equals(sdName)) { 144 | found = true; 145 | break; 146 | } 147 | } 148 | if (! found) { 149 | throw new IllegalArgumentException("SD-ID is not known registered SDID: " + sdName); 150 | } 151 | } 152 | } 153 | 154 | } 155 | -------------------------------------------------------------------------------- /src/main/java/com/cloudbees/syslog/SDParam.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2010-2014, CloudBees Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.cloudbees.syslog; 17 | 18 | import java.io.Serializable; 19 | import java.util.Objects; 20 | 21 | /** 22 | * 23 | * @author Brett Bergquist 24 | */ 25 | public class SDParam implements Serializable { 26 | 27 | private static final long serialVersionUID = 1L; 28 | 29 | public SDParam(String paramName, String paramValue) { 30 | validateParamName(paramName); 31 | this.paramName = paramName; 32 | this.paramValue = paramValue; 33 | } 34 | 35 | private String paramName; 36 | 37 | /** 38 | * Get the value of paramName 39 | * 40 | * @return the value of paramName 41 | */ 42 | public String getParamName() { 43 | return paramName; 44 | } 45 | 46 | /** 47 | * Set the value of paramName 48 | * 49 | * @param paramName new value of paramName 50 | */ 51 | public void setParamName(String paramName) { 52 | validateParamName(paramName); 53 | this.paramName = paramName; 54 | } 55 | 56 | private String paramValue; 57 | 58 | /** 59 | * Get the value of paramValue 60 | * 61 | * @return the value of paramValue 62 | */ 63 | public String getParamValue() { 64 | return paramValue; 65 | } 66 | 67 | /** 68 | * Set the value of paramValue 69 | * 70 | * @param paramValue new value of paramValue 71 | */ 72 | public void setParamValue(String paramValue) { 73 | this.paramValue = paramValue; 74 | } 75 | 76 | private void validateParamName(String sdName) { 77 | if (null == sdName) { 78 | throw new IllegalArgumentException("PARAM-NAME cannot be null"); 79 | } 80 | if (sdName.length() > 32) { 81 | throw new IllegalArgumentException("PARAM-NAME must be less than 32 characters: " + sdName); 82 | } 83 | if (sdName.contains("=")) { 84 | throw new IllegalArgumentException("PARAM-NAME cannot contain '='"); 85 | } 86 | if (sdName.contains(" ")) { 87 | throw new IllegalArgumentException("PARAM-NAME cannot contain ' '"); 88 | } 89 | if (sdName.contains("]")) { 90 | throw new IllegalArgumentException("PARAM-NAME cannot contain ']'"); 91 | } 92 | if (sdName.contains("\"")) { 93 | throw new IllegalArgumentException("PARAM-NAME cannot contain '\"'"); 94 | } 95 | } 96 | 97 | @Override 98 | public int hashCode() { 99 | int hash = 7; 100 | hash = 59 * hash + Objects.hashCode(this.paramName); 101 | hash = 59 * hash + Objects.hashCode(this.paramValue); 102 | return hash; 103 | } 104 | 105 | @Override 106 | public boolean equals(Object obj) { 107 | if (this == obj) { 108 | return true; 109 | } 110 | if (obj == null) { 111 | return false; 112 | } 113 | if (getClass() != obj.getClass()) { 114 | return false; 115 | } 116 | final SDParam other = (SDParam) obj; 117 | if (!Objects.equals(this.paramName, other.paramName)) { 118 | return false; 119 | } 120 | if (!Objects.equals(this.paramValue, other.paramValue)) { 121 | return false; 122 | } 123 | return true; 124 | } 125 | 126 | @Override 127 | public String toString() { 128 | return "SDParam{" + "paramName=" + paramName + ", paramValue=" + paramValue + '}'; 129 | } 130 | 131 | } 132 | -------------------------------------------------------------------------------- /src/main/java/com/cloudbees/syslog/Severity.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2010-2014, CloudBees Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.cloudbees.syslog; 17 | 18 | import edu.umd.cs.findbugs.annotations.NonNull; 19 | import edu.umd.cs.findbugs.annotations.Nullable; 20 | import java.util.Comparator; 21 | import java.util.HashMap; 22 | import java.util.Map; 23 | 24 | /** 25 | * Syslog severity as defined in RFC 5424 - The Syslog Protocol. 26 | * 27 | * @author Cyrille Le Clerc 28 | */ 29 | public enum Severity { 30 | /** 31 | * Emergency: system is unusable, numerical code 0. 32 | */ 33 | EMERGENCY(0, "EMERGENCY"), 34 | /** 35 | * Alert: action must be taken immediately, numerical code 1. 36 | */ 37 | ALERT(1, "ALERT"), 38 | /** 39 | * Critical: critical conditions, numerical code 2. 40 | */ 41 | CRITICAL(2, "CRITICAL"), 42 | /** 43 | * Error: error conditions, numerical code 3. 44 | */ 45 | ERROR(3, "ERROR"), 46 | /** 47 | * Warning: warning conditions, numerical code 4. 48 | */ 49 | WARNING(4, "WARNING"), 50 | /** 51 | * Notice: normal but significant condition, numerical code 5. 52 | */ 53 | NOTICE(5, "NOTICE"), 54 | /** 55 | * Informational: informational messages, numerical code 6. 56 | */ 57 | INFORMATIONAL(6, "INFORMATIONAL"), 58 | /** 59 | * Debug: debug-level messages, numerical code 7. 60 | */ 61 | DEBUG(7, "DEBUG"); 62 | 63 | // mapping 64 | private final static Map severityFromLabel = new HashMap<>(); 65 | private final static Map severityFromNumericalCode = new HashMap<>(); 66 | 67 | static { 68 | for (Severity severity : Severity.values()) { 69 | severityFromLabel.put(severity.label, severity); 70 | severityFromNumericalCode.put(severity.numericalCode, severity); 71 | } 72 | } 73 | 74 | private final int numericalCode; 75 | @NonNull 76 | private final String label; 77 | 78 | Severity(int numericalCode, @NonNull String label) { 79 | this.numericalCode = numericalCode; 80 | this.label = label; 81 | } 82 | 83 | /** 84 | * @param numericalCode Syslog severity numerical code 85 | * @return Syslog severity, not {@code null} 86 | * @throws IllegalArgumentException the given numericalCode is not a valid Syslog severity numerical code 87 | */ 88 | public static Severity fromNumericalCode(int numericalCode) throws IllegalArgumentException { 89 | Severity severity = severityFromNumericalCode.get(numericalCode); 90 | if (severity == null) { 91 | throw new IllegalArgumentException("Invalid severity '" + numericalCode + "'"); 92 | } 93 | return severity; 94 | } 95 | 96 | /** 97 | * @param label Syslog severity textual code. {@code null} or empty returns {@code null} 98 | * @return Syslog severity, {@code null} if given value is {@code null} 99 | * @throws IllegalArgumentException the given value is not a valid Syslog severity textual code 100 | */ 101 | @Nullable 102 | public static Severity fromLabel(@Nullable String label) throws IllegalArgumentException { 103 | if (label == null || label.isEmpty()) 104 | return null; 105 | 106 | Severity severity = severityFromLabel.get(label); 107 | if (severity == null) { 108 | throw new IllegalArgumentException("Invalid severity '" + label + "'"); 109 | } 110 | return severity; 111 | } 112 | 113 | /** 114 | * Syslog severity numerical code 115 | */ 116 | public int numericalCode() { 117 | return numericalCode; 118 | } 119 | 120 | /** 121 | * Syslog severity textual code. Not {@code null}. 122 | */ 123 | @NonNull 124 | public String label() { 125 | return label; 126 | } 127 | 128 | /** 129 | * Compare on {@link Severity#numericalCode()} 130 | */ 131 | public static Comparator comparator() { 132 | return Comparator.comparingInt(s -> s.numericalCode); 133 | } 134 | } 135 | 136 | -------------------------------------------------------------------------------- /src/main/java/com/cloudbees/syslog/SyslogMessage.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2010-2014, CloudBees Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.cloudbees.syslog; 17 | 18 | import edu.umd.cs.findbugs.annotations.NonNull; 19 | import edu.umd.cs.findbugs.annotations.Nullable; 20 | 21 | import java.io.CharArrayWriter; 22 | import java.io.IOException; 23 | import java.io.StringWriter; 24 | import java.io.Writer; 25 | import java.net.InetAddress; 26 | import java.net.UnknownHostException; 27 | import java.nio.charset.StandardCharsets; 28 | import java.util.Date; 29 | import java.util.HashSet; 30 | import java.util.Locale; 31 | import java.util.Set; 32 | import java.util.TimeZone; 33 | import java.util.concurrent.TimeUnit; 34 | 35 | import com.cloudbees.syslog.util.CachingReference; 36 | import com.cloudbees.syslog.util.ConcurrentDateFormat; 37 | 38 | /** 39 | * Syslog message as defined in RFC 5424 - The Syslog Protocol. 40 | * 41 | * Also compatible with RFC-3164: The BSD syslog Protocol, 42 | * 43 | * @author Cyrille Le Clerc 44 | */ 45 | public class SyslogMessage { 46 | public final static char SP = ' '; 47 | public final static char NILVALUE = '-'; 48 | 49 | private final static int DEFAULT_CONCURRENCY = 50; 50 | protected final static ConcurrentDateFormat rfc3339DateFormat; 51 | protected final static ConcurrentDateFormat rfc3164DateFormat; 52 | private static CachingReference localhostNameReference = new CachingReference(10, TimeUnit.SECONDS) { 53 | @Override 54 | protected String newObject() { 55 | try { 56 | return InetAddress.getLocalHost().getHostName(); 57 | } catch (UnknownHostException e) { 58 | return String.valueOf(NILVALUE); 59 | } 60 | } 61 | }; 62 | 63 | static { 64 | int concurrency; 65 | try { 66 | concurrency = Integer.parseInt(System.getProperty(SyslogMessage.class.getPackage().getName() + ".concurrency", String.valueOf(DEFAULT_CONCURRENCY))); 67 | } catch (Exception e) { 68 | concurrency = DEFAULT_CONCURRENCY; 69 | } 70 | 71 | rfc3339DateFormat = new ConcurrentDateFormat( 72 | "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'", 73 | Locale.US, 74 | TimeZone.getTimeZone("GMT"), 75 | concurrency); 76 | 77 | /* 78 | * According to RFC31614- 4.1.2 HEADER Part of a syslog Packet, 79 | * we should use local time and not GMT. 80 | * 81 | * The TIMESTAMP field is the local time and is in the format of "Mmm dd hh:mm:ss" (without the quote marks) 82 | * 83 | */ 84 | rfc3164DateFormat = new ConcurrentDateFormat( 85 | "MMM dd HH:mm:ss", 86 | Locale.US, 87 | TimeZone.getDefault(), 88 | concurrency); 89 | } 90 | 91 | private Facility facility; 92 | private Severity severity; 93 | private Long timestamp; 94 | private String hostname; 95 | private String appName; 96 | private String procId; 97 | private String msgId; 98 | private Set sdElements; 99 | /** 100 | * Use a {@link java.io.CharArrayWriter} instead of a {@link String} or a {@code char[]} because middlewares like 101 | * Apache Tomcat use {@code CharArrayWriter} and it's convenient for pooling objects. 102 | */ 103 | private CharArrayWriter msg; 104 | 105 | public Facility getFacility() { 106 | return facility; 107 | } 108 | 109 | public void setFacility(Facility facility) { 110 | this.facility = facility; 111 | } 112 | 113 | public SyslogMessage withFacility(Facility facility) { 114 | this.facility = facility; 115 | return this; 116 | } 117 | 118 | public Severity getSeverity() { 119 | return severity; 120 | } 121 | 122 | public void setSeverity(Severity severity) { 123 | this.severity = severity; 124 | } 125 | 126 | public SyslogMessage withSeverity(Severity severity) { 127 | this.severity = severity; 128 | return this; 129 | } 130 | 131 | public Date getTimestamp() { 132 | return timestamp == null ? null : new Date(timestamp); 133 | } 134 | 135 | public void setTimestamp(Date timestamp) { 136 | this.timestamp = timestamp == null ? null : timestamp.getTime(); 137 | } 138 | 139 | public SyslogMessage withTimestamp(long timestamp) { 140 | this.timestamp = timestamp; 141 | return this; 142 | } 143 | 144 | public SyslogMessage withTimestamp(Date timestamp) { 145 | this.timestamp = timestamp == null ? null : timestamp.getTime(); 146 | return this; 147 | } 148 | 149 | public String getHostname() { 150 | return hostname; 151 | } 152 | 153 | public void setHostname(String hostname) { 154 | this.hostname = hostname; 155 | } 156 | 157 | public SyslogMessage withHostname(String hostname) { 158 | this.hostname = hostname; 159 | return this; 160 | } 161 | 162 | public String getAppName() { 163 | return appName; 164 | } 165 | 166 | public void setAppName(String appName) { 167 | this.appName = appName; 168 | } 169 | 170 | public SyslogMessage withAppName(String appName) { 171 | this.appName = appName; 172 | return this; 173 | } 174 | 175 | public String getProcId() { 176 | return procId; 177 | } 178 | 179 | public void setProcId(String procId) { 180 | this.procId = procId; 181 | } 182 | 183 | public SyslogMessage withProcId(String procId) { 184 | this.procId = procId; 185 | return this; 186 | } 187 | 188 | public String getMsgId() { 189 | return msgId; 190 | } 191 | 192 | public void setMsgId(String msgId) { 193 | this.msgId = msgId; 194 | } 195 | 196 | public SyslogMessage withMsgId(String msgId) { 197 | this.msgId = msgId; 198 | return this; 199 | } 200 | 201 | public CharArrayWriter getMsg() { 202 | return msg; 203 | } 204 | 205 | public void setMsg(CharArrayWriter msg) { 206 | this.msg = msg; 207 | } 208 | 209 | public SyslogMessage withMsg(CharArrayWriter msg) { 210 | this.msg = msg; 211 | return this; 212 | } 213 | 214 | public SyslogMessage withMsg(final String msg) { 215 | return withMsg(new CharArrayWriter() { 216 | { 217 | append(msg); 218 | } 219 | }); 220 | } 221 | 222 | public Set getSDElements() { 223 | Set ssde = sdElements; 224 | if (ssde == null) { 225 | ssde = new HashSet<>(0); 226 | } 227 | return ssde; 228 | } 229 | 230 | public void setSDElements(Set ssde) { 231 | this.sdElements = ssde; 232 | } 233 | 234 | public SyslogMessage withSDElement(SDElement sde) { 235 | if (sdElements == null) { 236 | sdElements = new HashSet<>(); 237 | } 238 | sdElements.add(sde); 239 | return this; 240 | } 241 | 242 | /** 243 | * Generates a Syslog message complying to the RFC-5424 format 244 | * or to the RFC-3164 format. 245 | * 246 | * @param messageFormat message format, not {@code null} 247 | */ 248 | public String toSyslogMessage(MessageFormat messageFormat) { 249 | switch (messageFormat) { 250 | case RFC_3164: 251 | return toRfc3164SyslogMessage(); 252 | case RFC_5424: 253 | return toRfc5424SyslogMessage(); 254 | case RFC_5425: 255 | return toRfc5425SyslogMessage(); 256 | default: 257 | throw new IllegalStateException("Unsupported message format '" + messageFormat + "'"); 258 | } 259 | } 260 | 261 | /** 262 | * Generates a Syslog message complying to the RFC-5424 format 263 | * or to the RFC-3164 format. 264 | * 265 | * @param messageFormat message format 266 | * @param out output {@linkplain Writer} 267 | */ 268 | public void toSyslogMessage(@NonNull MessageFormat messageFormat, @NonNull Writer out) throws IOException { 269 | switch (messageFormat) { 270 | case RFC_3164: 271 | toRfc3164SyslogMessage(out); 272 | break; 273 | case RFC_5424: 274 | toRfc5424SyslogMessage(out); 275 | break; 276 | case RFC_5425: 277 | toRfc5425SyslogMessage(out); 278 | break; 279 | default: 280 | throw new IllegalStateException("Unsupported message format '" + messageFormat + "'"); 281 | } 282 | } 283 | 284 | /** 285 | * Generates an RFC-5425 message. 286 | */ 287 | public String toRfc5425SyslogMessage() { 288 | 289 | StringWriter sw = new StringWriter(msg == null ? 32 : msg.size() + 32); 290 | try { 291 | toRfc5425SyslogMessage(sw); 292 | } catch (IOException e) { 293 | throw new IllegalStateException(e); 294 | } 295 | return sw.toString(); 296 | } 297 | 298 | /** 299 | * Generates an RFC-5425 message. 300 | */ 301 | public void toRfc5425SyslogMessage(Writer out) throws IOException { 302 | 303 | String rfc5424Message = toRfc5424SyslogMessage(); 304 | int length = rfc5424Message.getBytes(StandardCharsets.UTF_8).length; 305 | out.write(String.valueOf(length)); 306 | out.write(SP); 307 | out.write(rfc5424Message); 308 | } 309 | 310 | /** 311 | * Generates an RFC-5424 message. 312 | */ 313 | public String toRfc5424SyslogMessage() { 314 | 315 | StringWriter sw = new StringWriter(msg == null ? 32 : msg.size() + 32); 316 | try { 317 | toRfc5424SyslogMessage(sw); 318 | } catch (IOException e) { 319 | throw new IllegalStateException(e); 320 | } 321 | return sw.toString(); 322 | } 323 | 324 | /** 325 | * Generates an RFC-5424 message. 326 | * 327 | * The priority is calculated by facility * 8 + severity, see 328 | * RFC-5424, Section 6.2.1 329 | */ 330 | public void toRfc5424SyslogMessage(Writer out) throws IOException { 331 | 332 | int pri = facility.numericalCode() * 8 + severity.numericalCode(); 333 | 334 | out.write('<'); 335 | out.write(String.valueOf(pri)); 336 | out.write('>'); 337 | out.write('1'); // version 338 | out.write(SP); 339 | out.write(rfc3339DateFormat.format(timestamp == null ? new Date() : new Date(timestamp))); // message time 340 | out.write(SP); 341 | out.write(hostname == null ? localhostNameReference.get() : hostname); // emitting server hostname 342 | out.write(SP); 343 | writeNillableValue(appName, out); // appname 344 | out.write(SP); 345 | writeNillableValue(procId, out); // PID 346 | out.write(SP); 347 | writeNillableValue(msgId, out);// Message ID 348 | out.write(SP); 349 | writeStructuredDataOrNillableValue(sdElements, out); 350 | if (msg != null) { 351 | out.write(SP); 352 | msg.writeTo(out); 353 | } 354 | } 355 | 356 | /** 357 | * Generates an RFC-3164 message. 358 | * 359 | * @see #toRfc3164SyslogMessage(java.io.Writer) 360 | */ 361 | public String toRfc3164SyslogMessage() { 362 | 363 | StringWriter sw = new StringWriter(msg == null ? 32 : msg.size() + 32); 364 | try { 365 | toRfc3164SyslogMessage(sw); 366 | } catch (IOException e) { 367 | throw new IllegalStateException(e); 368 | } 369 | return sw.toString(); 370 | } 371 | 372 | /** 373 | * Generates an RFC-3164 message. 374 | */ 375 | public void toRfc3164SyslogMessage(Writer out) throws IOException { 376 | 377 | int pri = facility.numericalCode() * 8 + severity.numericalCode(); 378 | 379 | out.write('<'); 380 | out.write(Integer.toString(pri)); 381 | out.write('>'); 382 | out.write(rfc3164DateFormat.format(timestamp == null ? new Date() : new Date(timestamp))); // message time 383 | out.write(SP); 384 | out.write(hostname == null ? localhostNameReference.get() : hostname); // emitting server hostname 385 | out.write(SP); 386 | writeNillableValue(appName, out); // appname 387 | 388 | if (msg != null) { 389 | out.write(": "); 390 | msg.writeTo(out); 391 | } 392 | } 393 | 394 | protected void writeNillableValue(@Nullable String value, @NonNull Writer out) throws IOException { 395 | if (value == null) { 396 | out.write(NILVALUE); 397 | } else { 398 | out.write(value); 399 | } 400 | } 401 | 402 | protected void writeStructuredDataOrNillableValue(@Nullable Set ssde, @NonNull Writer out) throws IOException { 403 | if (ssde == null || ssde.isEmpty()) { 404 | out.write(NILVALUE); 405 | } else { 406 | for (SDElement sde : ssde) { 407 | writeSDElement(sde, out); 408 | } 409 | } 410 | } 411 | 412 | protected void writeSDElement(@NonNull SDElement sde, @NonNull Writer out) throws IOException { 413 | out.write("["); 414 | out.write(sde.getSdID()); 415 | for (SDParam sdp : sde.getSdParams()) { 416 | writeSDParam(sdp, out); 417 | } 418 | out.write("]"); 419 | } 420 | 421 | protected void writeSDParam(@NonNull SDParam sdp, @NonNull Writer out) throws IOException { 422 | out.write(SP); 423 | out.write(sdp.getParamName()); 424 | out.write('='); 425 | out.write('"'); 426 | out.write(getEscapedParamValue(sdp.getParamValue())); 427 | out.write('"'); 428 | } 429 | 430 | protected String getEscapedParamValue(String paramValue) { 431 | StringBuilder sb = new StringBuilder(paramValue.length()); 432 | 433 | for (int i = 0; i < paramValue.length(); i++) { 434 | char c = paramValue.charAt(i); 435 | switch (c) { 436 | // Falls through 437 | case '"': 438 | case '\\': 439 | case ']': 440 | sb.append('\\'); 441 | break; 442 | default: 443 | break; 444 | } 445 | sb.append(c); 446 | } 447 | 448 | return sb.toString(); 449 | } 450 | } 451 | -------------------------------------------------------------------------------- /src/main/java/com/cloudbees/syslog/integration/jul/AbstractHandler.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2010-2013 the original author or authors 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining 5 | * a copy of this software and associated documentation files (the 6 | * "Software"), to deal in the Software without restriction, including 7 | * without limitation the rights to use, copy, modify, merge, publish, 8 | * distribute, sublicense, and/or sell copies of the Software, and to 9 | * permit persons to whom the Software is furnished to do so, subject to 10 | * the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be 13 | * included in all copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 19 | * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 20 | * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 21 | * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | * 23 | */ 24 | package com.cloudbees.syslog.integration.jul; 25 | 26 | import com.cloudbees.syslog.integration.jul.util.LogManagerHelper; 27 | 28 | import edu.umd.cs.findbugs.annotations.NonNull; 29 | import edu.umd.cs.findbugs.annotations.Nullable; 30 | import java.util.logging.Filter; 31 | import java.util.logging.Formatter; 32 | import java.util.logging.Handler; 33 | import java.util.logging.Level; 34 | import java.util.logging.LogManager; 35 | import java.util.logging.LogRecord; 36 | import java.util.logging.SimpleFormatter; 37 | 38 | /** 39 | * @author Cyrille Le Clerc 40 | */ 41 | public abstract class AbstractHandler extends Handler { 42 | 43 | private Level logLevel = Level.ALL; 44 | private Filter filter; 45 | private Formatter formatter; 46 | 47 | public AbstractHandler() { 48 | super(); 49 | LogManager manager = LogManager.getLogManager(); 50 | String cname = getClass().getName(); 51 | this.logLevel = LogManagerHelper.getLevelProperty(manager, cname + ".level", Level.INFO); 52 | this.filter = LogManagerHelper.getFilterProperty(manager, cname + ".filter", null); 53 | this.formatter = LogManagerHelper.getFormatterProperty(manager, cname + ".formatter", getDefaultFormatter()); 54 | } 55 | 56 | 57 | public AbstractHandler(@NonNull Level level, @Nullable Filter filter) { 58 | this.logLevel = level; 59 | this.filter = filter; 60 | this.formatter = getDefaultFormatter(); 61 | } 62 | 63 | 64 | /** 65 | * For extensibility 66 | * 67 | * @return 68 | */ 69 | @NonNull 70 | protected Formatter getDefaultFormatter() { 71 | return new SimpleFormatter(); 72 | } 73 | 74 | 75 | /** 76 | * {@inheritDoc} 77 | */ 78 | @Override 79 | public boolean isLoggable(LogRecord record) { 80 | if (record == null) { 81 | return false; 82 | } 83 | return super.isLoggable(record); 84 | } 85 | 86 | /** 87 | * {@inheritDoc} 88 | */ 89 | @Override 90 | public Level getLevel() { 91 | return this.logLevel; 92 | } 93 | 94 | /** 95 | * {@inheritDoc} 96 | */ 97 | @Nullable 98 | @Override 99 | public Filter getFilter() { 100 | return filter; 101 | } 102 | 103 | /** 104 | * {@inheritDoc} 105 | */ 106 | @Override 107 | public Formatter getFormatter() { 108 | return formatter; 109 | } 110 | 111 | /** 112 | * {@inheritDoc} 113 | */ 114 | @Override 115 | public void setFormatter(Formatter formatter) throws SecurityException { 116 | this.formatter = formatter; 117 | } 118 | } 119 | -------------------------------------------------------------------------------- /src/main/java/com/cloudbees/syslog/integration/jul/SyslogHandler.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2010-2013 the original author or authors 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining 5 | * a copy of this software and associated documentation files (the 6 | * "Software"), to deal in the Software without restriction, including 7 | * without limitation the rights to use, copy, modify, merge, publish, 8 | * distribute, sublicense, and/or sell copies of the Software, and to 9 | * permit persons to whom the Software is furnished to do so, subject to 10 | * the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be 13 | * included in all copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 19 | * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 20 | * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 21 | * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | * 23 | */ 24 | package com.cloudbees.syslog.integration.jul; 25 | 26 | import com.cloudbees.syslog.Facility; 27 | import com.cloudbees.syslog.Severity; 28 | import com.cloudbees.syslog.SyslogMessage; 29 | import com.cloudbees.syslog.integration.jul.util.LevelHelper; 30 | import com.cloudbees.syslog.integration.jul.util.LogManagerHelper; 31 | import com.cloudbees.syslog.sender.SyslogMessageSender; 32 | import com.cloudbees.syslog.sender.UdpSyslogMessageSender; 33 | 34 | import edu.umd.cs.findbugs.annotations.NonNull; 35 | import edu.umd.cs.findbugs.annotations.Nullable; 36 | import java.io.IOException; 37 | import java.util.logging.Filter; 38 | import java.util.logging.Formatter; 39 | import java.util.logging.Level; 40 | import java.util.logging.LogManager; 41 | import java.util.logging.LogRecord; 42 | 43 | /** 44 | * @author Cyrille Le Clerc 45 | */ 46 | public class SyslogHandler extends AbstractHandler { 47 | 48 | private SyslogMessageSender syslogMessageSender; 49 | 50 | private String appName; 51 | private Facility facility = Facility.USER; 52 | private Severity severity = Severity.DEBUG; 53 | private String messageHostname; 54 | 55 | public SyslogHandler() { 56 | super(); 57 | LogManager manager = LogManager.getLogManager(); 58 | 59 | String cname = getClass().getName(); 60 | 61 | UdpSyslogMessageSender udpSender = new UdpSyslogMessageSender(); 62 | udpSender.setSyslogServerHostname(LogManagerHelper.getStringProperty(manager, cname + ".syslogServerHostname", SyslogMessageSender.DEFAULT_SYSLOG_HOST)); 63 | udpSender.setSyslogServerPort(LogManagerHelper.getIntProperty(manager, cname + ".syslogServerPort", SyslogMessageSender.DEFAULT_SYSLOG_PORT)); 64 | 65 | appName = LogManagerHelper.getStringProperty(manager, cname + ".appName", this.appName); 66 | udpSender.setDefaultAppName(appName); 67 | facility = Facility.fromLabel(LogManagerHelper.getStringProperty(manager, cname + ".facility", this.facility.label())); 68 | udpSender.setDefaultFacility(facility); 69 | severity = Severity.fromLabel(LogManagerHelper.getStringProperty(manager, cname + ".severity", this.severity.label())); 70 | udpSender.setDefaultSeverity(severity); 71 | messageHostname = LogManagerHelper.getStringProperty(manager, cname + ".messageHostname", this.messageHostname); 72 | udpSender.setDefaultMessageHostname(messageHostname); 73 | 74 | this.syslogMessageSender = udpSender; 75 | } 76 | 77 | public SyslogHandler(@NonNull SyslogMessageSender syslogMessageSender) { 78 | this(syslogMessageSender, Level.INFO, null); 79 | } 80 | 81 | public SyslogHandler(@NonNull SyslogMessageSender syslogMessageSender, @NonNull Level level, @Nullable Filter filter) { 82 | super(level, filter); 83 | this.syslogMessageSender = syslogMessageSender; 84 | } 85 | 86 | @NonNull 87 | @Override 88 | protected Formatter getDefaultFormatter() { 89 | return new SyslogMessageFormatter(); 90 | } 91 | 92 | @Override 93 | public void publish(LogRecord record) { 94 | if (!isLoggable(record)) 95 | return; 96 | 97 | String msg = getFormatter().format(record); 98 | 99 | Severity severity = LevelHelper.toSeverity(record.getLevel()); 100 | if (severity == null) 101 | severity = this.severity; 102 | 103 | SyslogMessage message = new SyslogMessage() 104 | .withTimestamp(record.getMillis()) 105 | .withSeverity(severity) 106 | .withAppName(this.appName) 107 | .withHostname(this.messageHostname) 108 | .withFacility(this.facility) 109 | .withMsg(msg); 110 | 111 | try { 112 | syslogMessageSender.sendMessage(message); 113 | } catch (IOException e) { 114 | e.printStackTrace(); 115 | } 116 | } 117 | 118 | @Override 119 | public void flush() { 120 | 121 | } 122 | 123 | @Override 124 | public void close() throws SecurityException { 125 | try { 126 | syslogMessageSender.close(); 127 | } catch (IOException e) { 128 | e.printStackTrace(); 129 | } 130 | } 131 | 132 | @Override 133 | public String getEncoding() { 134 | throw new IllegalStateException(); 135 | } 136 | 137 | public String getAppName() { 138 | return appName; 139 | } 140 | 141 | public void setAppName(String appName) { 142 | this.appName = appName; 143 | } 144 | 145 | public Facility getFacility() { 146 | return facility; 147 | } 148 | 149 | public void setFacility(Facility facility) { 150 | this.facility = facility; 151 | } 152 | 153 | public Severity getSeverity() { 154 | return severity; 155 | } 156 | 157 | public void setSeverity(Severity severity) { 158 | this.severity = severity; 159 | } 160 | 161 | public String getMessageHostname() { 162 | return messageHostname; 163 | } 164 | 165 | public void setMessageHostname(String messageHostname) { 166 | this.messageHostname = messageHostname; 167 | } 168 | 169 | public SyslogMessageSender getSyslogMessageSender() { 170 | return syslogMessageSender; 171 | } 172 | 173 | public void setSyslogMessageSender(SyslogMessageSender syslogMessageSender) { 174 | this.syslogMessageSender = syslogMessageSender; 175 | } 176 | } 177 | -------------------------------------------------------------------------------- /src/main/java/com/cloudbees/syslog/integration/jul/SyslogMessageFormatter.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2010-2013 the original author or authors 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining 5 | * a copy of this software and associated documentation files (the 6 | * "Software"), to deal in the Software without restriction, including 7 | * without limitation the rights to use, copy, modify, merge, publish, 8 | * distribute, sublicense, and/or sell copies of the Software, and to 9 | * permit persons to whom the Software is furnished to do so, subject to 10 | * the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be 13 | * included in all copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 19 | * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 20 | * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 21 | * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | * 23 | */ 24 | package com.cloudbees.syslog.integration.jul; 25 | 26 | import java.io.PrintWriter; 27 | import java.io.StringWriter; 28 | import java.util.logging.Formatter; 29 | import java.util.logging.LogRecord; 30 | 31 | /** 32 | * @author Cyrille Le Clerc 33 | */ 34 | public class SyslogMessageFormatter extends Formatter { 35 | 36 | @Override 37 | public String format(LogRecord record) { 38 | String message = formatMessage(record); 39 | String throwable = ""; 40 | if (record.getThrown() != null) { 41 | StringWriter sw = new StringWriter(); 42 | PrintWriter pw = new PrintWriter(sw); 43 | pw.println(); 44 | record.getThrown().printStackTrace(pw); 45 | pw.close(); 46 | throwable = sw.toString(); 47 | } 48 | return record.getLevel() + " [" + Thread.currentThread().getName() + "] " + record.getLoggerName() + ": " + message + throwable; 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/main/java/com/cloudbees/syslog/integration/jul/util/LevelHelper.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2010-2013 the original author or authors 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining 5 | * a copy of this software and associated documentation files (the 6 | * "Software"), to deal in the Software without restriction, including 7 | * without limitation the rights to use, copy, modify, merge, publish, 8 | * distribute, sublicense, and/or sell copies of the Software, and to 9 | * permit persons to whom the Software is furnished to do so, subject to 10 | * the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be 13 | * included in all copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 19 | * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 20 | * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 21 | * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | * 23 | */ 24 | package com.cloudbees.syslog.integration.jul.util; 25 | 26 | import com.cloudbees.syslog.Severity; 27 | 28 | import edu.umd.cs.findbugs.annotations.Nullable; 29 | import java.util.Arrays; 30 | import java.util.Collections; 31 | import java.util.Comparator; 32 | import java.util.HashMap; 33 | import java.util.List; 34 | import java.util.Map; 35 | import java.util.logging.Level; 36 | 37 | /** 38 | * @author Cyrille Le Clerc 39 | */ 40 | public class LevelHelper { 41 | 42 | public final static List levels = Collections.unmodifiableList(Arrays.asList(Level.OFF, Level.SEVERE, Level.WARNING, Level.INFO, Level.CONFIG, 43 | Level.FINE, Level.FINER, Level.FINEST, Level.ALL)); 44 | 45 | public final static Map levelsByName; 46 | public final static Map levelsByValue; 47 | private final static Map julLevelToSyslogSeverity; 48 | 49 | static { 50 | Map levelsByNameMap = new HashMap<>(); 51 | Map levelsByValueMap = new HashMap<>(); 52 | for (Level level : levels) { 53 | levelsByNameMap.put(level.getName(), level); 54 | levelsByValueMap.put(level.intValue(), level); 55 | } 56 | levelsByName = Collections.unmodifiableMap(levelsByNameMap); 57 | levelsByValue = Collections.unmodifiableMap(levelsByValueMap); 58 | 59 | julLevelToSyslogSeverity = Collections.unmodifiableMap(new HashMap() { 60 | { 61 | put(Level.CONFIG, Severity.INFORMATIONAL); 62 | put(Level.FINE, Severity.DEBUG); 63 | put(Level.FINER, Severity.DEBUG); 64 | put(Level.FINEST, Severity.DEBUG); 65 | put(Level.INFO, Severity.INFORMATIONAL); 66 | put(Level.SEVERE, Severity.ERROR); 67 | put(Level.WARNING, Severity.WARNING); 68 | } 69 | }); 70 | } 71 | 72 | /** 73 | * Simplification: use delegate to {@link Level#parse(String)} even if the behavior is slightly different for localized log levels. 74 | * 75 | * @param name {@code null} or empty returns {@code null} 76 | * @return 77 | */ 78 | @Nullable 79 | public static Level findLevel(@Nullable String name) { 80 | if(name == null || name.isEmpty()) 81 | return null; 82 | return Level.parse(name); 83 | 84 | } 85 | 86 | @Nullable 87 | public static Severity toSeverity(@Nullable Level level) { 88 | return julLevelToSyslogSeverity.get(level); 89 | } 90 | 91 | /** 92 | * Compare on {@link java.util.logging.Level#intValue()} 93 | */ 94 | public static Comparator comparator() { 95 | return Comparator.comparingInt(Level::intValue); 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /src/main/java/com/cloudbees/syslog/integration/jul/util/LogManagerHelper.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2010-2013 the original author or authors 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining 5 | * a copy of this software and associated documentation files (the 6 | * "Software"), to deal in the Software without restriction, including 7 | * without limitation the rights to use, copy, modify, merge, publish, 8 | * distribute, sublicense, and/or sell copies of the Software, and to 9 | * permit persons to whom the Software is furnished to do so, subject to 10 | * the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be 13 | * included in all copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 19 | * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 20 | * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 21 | * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | * 23 | */ 24 | package com.cloudbees.syslog.integration.jul.util; 25 | 26 | import edu.umd.cs.findbugs.annotations.NonNull; 27 | import edu.umd.cs.findbugs.annotations.Nullable; 28 | import java.util.logging.Filter; 29 | import java.util.logging.Formatter; 30 | import java.util.logging.Level; 31 | import java.util.logging.LogManager; 32 | 33 | /** 34 | * @author Cyrille Le Clerc 35 | */ 36 | public class LogManagerHelper { 37 | 38 | /** 39 | * Visible version of {@link java.util.logging.LogManager#getLevelProperty(String, java.util.logging.Level)}. 40 | * 41 | * If the property is not defined or cannot be parsed we return the given default value. 42 | */ 43 | @Nullable 44 | public static Level getLevelProperty(@NonNull LogManager manager, @NonNull String name, @Nullable Level defaultValue) { 45 | if (name == null) { 46 | return defaultValue; 47 | } 48 | String val = manager.getProperty(name); 49 | if (val == null) { 50 | return defaultValue; 51 | } 52 | Level l = LevelHelper.findLevel(val.trim()); 53 | return l != null ? l : defaultValue; 54 | } 55 | 56 | 57 | /** 58 | * Visible version of {@link java.util.logging.LogManager#getFilterProperty(String, java.util.logging.Filter)}. 59 | * 60 | * We return an instance of the class named by the "name" property. 61 | * 62 | * If the property is not defined or has problems we return the defaultValue. 63 | */ 64 | @Nullable 65 | public static Filter getFilterProperty(@NonNull LogManager manager, @Nullable String name, @Nullable Filter defaultValue) { 66 | if (name == null) { 67 | return defaultValue; 68 | } 69 | String val = manager.getProperty(name); 70 | try { 71 | if (val != null) { 72 | Class clz = ClassLoader.getSystemClassLoader().loadClass(val); 73 | return (Filter) clz.newInstance(); 74 | } 75 | } catch (Exception ex) { 76 | // We got one of a variety of exceptions in creating the 77 | // class or creating an instance. 78 | // Drop through. 79 | } 80 | // We got an exception. Return the defaultValue. 81 | return defaultValue; 82 | } 83 | 84 | 85 | /** 86 | * Visible version of {@link java.util.logging.LogManager#getFormatterProperty(String, java.util.logging.Formatter)} . 87 | * 88 | * We return an instance of the class named by the "name" property. 89 | * 90 | * If the property is not defined or has problems we return the defaultValue. 91 | */ 92 | public static Formatter getFormatterProperty(@NonNull LogManager manager, @Nullable String name, @Nullable Formatter defaultValue) { 93 | if (name == null) { 94 | return defaultValue; 95 | } 96 | String val = manager.getProperty(name); 97 | try { 98 | if (val != null) { 99 | Class clz = ClassLoader.getSystemClassLoader().loadClass(val); 100 | return (Formatter) clz.newInstance(); 101 | } 102 | } catch (Exception ex) { 103 | // We got one of a variety of exceptions in creating the 104 | // class or creating an instance. 105 | // Drop through. 106 | } 107 | // We got an exception. Return the defaultValue. 108 | return defaultValue; 109 | } 110 | 111 | 112 | /** 113 | * Visible version of {@link java.util.logging.LogManager#getStringProperty(String, String)}. 114 | * 115 | * If the property is not defined we return the given default value. 116 | */ 117 | public static String getStringProperty(@NonNull LogManager manager, @Nullable String name, String defaultValue) { 118 | if (name == null) { 119 | return defaultValue; 120 | } 121 | String val = manager.getProperty(name); 122 | if (val == null) { 123 | return defaultValue; 124 | } 125 | return val.trim(); 126 | } 127 | 128 | 129 | /** 130 | * Visible version of {@link java.util.logging.LogManager#getIntProperty(String, int)}. 131 | * 132 | * Method to get an integer property. 133 | * 134 | * If the property is not defined or cannot be parsed we return the given default value. 135 | */ 136 | public static int getIntProperty(@NonNull LogManager manager, @Nullable String name, int defaultValue) { 137 | if (name == null) { 138 | return defaultValue; 139 | } 140 | String val = manager.getProperty(name); 141 | if (val == null) { 142 | return defaultValue; 143 | } 144 | try { 145 | return Integer.parseInt(val.trim()); 146 | } catch (Exception ex) { 147 | return defaultValue; 148 | } 149 | } 150 | 151 | 152 | /** 153 | * Visible version of {@link java.util.logging.LogManager#getIntProperty(String, int)}. 154 | * 155 | * Method to get a boolean property. 156 | * 157 | * If the property is not defined or cannot be parsed we return the given default value. 158 | */ 159 | public static boolean getBooleanProperty(@NonNull LogManager manager, @Nullable String name, boolean defaultValue) { 160 | if (name == null) { 161 | return defaultValue; 162 | } 163 | String val = manager.getProperty(name); 164 | if (val == null) { 165 | return defaultValue; 166 | } 167 | val = val.toLowerCase(); 168 | if (val.equals("true") || val.equals("1")) { 169 | return true; 170 | } else if (val.equals("false") || val.equals("0")) { 171 | return false; 172 | } 173 | return defaultValue; 174 | } 175 | 176 | 177 | } 178 | -------------------------------------------------------------------------------- /src/main/java/com/cloudbees/syslog/sender/AbstractSyslogMessageSender.java: -------------------------------------------------------------------------------- 1 | package com.cloudbees.syslog.sender; 2 | 3 | import com.cloudbees.syslog.Facility; 4 | import com.cloudbees.syslog.MessageFormat; 5 | import com.cloudbees.syslog.Severity; 6 | import com.cloudbees.syslog.SyslogMessage; 7 | import com.cloudbees.syslog.util.InternalLogger; 8 | 9 | import edu.umd.cs.findbugs.annotations.NonNull; 10 | import java.io.CharArrayWriter; 11 | import java.io.IOException; 12 | import java.nio.charset.Charset; 13 | import java.nio.charset.StandardCharsets; 14 | import java.util.concurrent.TimeUnit; 15 | import java.util.concurrent.atomic.AtomicInteger; 16 | import java.util.concurrent.atomic.AtomicLong; 17 | 18 | /** 19 | * @author Cyrille Le Clerc 20 | */ 21 | public abstract class AbstractSyslogMessageSender implements SyslogMessageSender { 22 | /** 23 | * @deprecated use {@link StandardCharsets#UTF_8} 24 | */ 25 | @Deprecated 26 | protected final static Charset UTF_8 = StandardCharsets.UTF_8; 27 | protected final InternalLogger logger = InternalLogger.getLogger(getClass()); 28 | // default values 29 | protected String defaultAppName; 30 | protected Facility defaultFacility = Facility.USER; 31 | protected String defaultMessageHostname; 32 | protected Severity defaultSeverity = Severity.INFORMATIONAL; 33 | // remote syslog server config 34 | /** 35 | * Format of messages accepted by the remote syslog server 36 | * ({@link com.cloudbees.syslog.MessageFormat#RFC_3164 RFC_3164} or 37 | * {@link com.cloudbees.syslog.MessageFormat#RFC_5424 RFC_5424}) 38 | */ 39 | protected MessageFormat messageFormat = DEFAULT_SYSLOG_MESSAGE_FORMAT; 40 | // statistics 41 | protected final AtomicInteger sendCounter = new AtomicInteger(); 42 | protected final AtomicLong sendDurationInNanosCounter = new AtomicLong(); 43 | protected final AtomicInteger sendErrorCounter = new AtomicInteger(); 44 | 45 | /** 46 | * Send the given text message 47 | * 48 | * @param message 49 | * @throws java.io.IOException 50 | */ 51 | @Override 52 | public void sendMessage(CharArrayWriter message) throws IOException { 53 | 54 | SyslogMessage syslogMessage = new SyslogMessage() 55 | .withAppName(defaultAppName) 56 | .withFacility(defaultFacility) 57 | .withHostname(defaultMessageHostname) 58 | .withSeverity(defaultSeverity) 59 | .withMsg(message); 60 | 61 | sendMessage(syslogMessage); 62 | } 63 | 64 | @Override 65 | public void sendMessage(CharSequence message) throws IOException { 66 | CharArrayWriter writer = new CharArrayWriter(); 67 | writer.append(message); 68 | sendMessage(writer); 69 | } 70 | 71 | /** 72 | * Send the given {@link com.cloudbees.syslog.SyslogMessage}. 73 | * 74 | * @param message the message to send 75 | * @throws IOException 76 | */ 77 | public abstract void sendMessage(@NonNull SyslogMessage message) throws IOException; 78 | 79 | public String getDefaultAppName() { 80 | return defaultAppName; 81 | } 82 | 83 | public Facility getDefaultFacility() { 84 | return defaultFacility; 85 | } 86 | 87 | public MessageFormat getMessageFormat() { 88 | return messageFormat; 89 | } 90 | 91 | public String getDefaultMessageHostname() { 92 | return defaultMessageHostname; 93 | } 94 | 95 | public int getSendCount() { 96 | return sendCounter.get(); 97 | } 98 | 99 | /** 100 | * Human readable view of {@link #getSendDurationInNanos()} 101 | * 102 | * @return total duration spent sending syslog messages 103 | */ 104 | public long getSendDurationInMillis() { 105 | return TimeUnit.MILLISECONDS.convert(getSendDurationInNanos(), TimeUnit.NANOSECONDS); 106 | } 107 | 108 | /** 109 | * Human readable view of {@link #getSendDurationInNanos()} 110 | * 111 | * @return total duration spent sending syslog messages 112 | */ 113 | public long getSendDurationInNanos() { 114 | return sendDurationInNanosCounter.get(); 115 | } 116 | 117 | public int getSendErrorCount() { 118 | return sendErrorCounter.get(); 119 | } 120 | 121 | public Severity getDefaultSeverity() { 122 | return defaultSeverity; 123 | } 124 | 125 | public void setDefaultAppName(String defaultAppName) { 126 | this.defaultAppName = defaultAppName; 127 | } 128 | 129 | public void setDefaultMessageHostname(String defaultHostname) { 130 | this.defaultMessageHostname = defaultHostname; 131 | } 132 | 133 | public void setDefaultFacility(Facility defaultFacility) { 134 | this.defaultFacility = defaultFacility; 135 | } 136 | 137 | public void setMessageFormat(MessageFormat messageFormat) { 138 | this.messageFormat = messageFormat; 139 | } 140 | 141 | public void setDefaultSeverity(Severity defaultSeverity) { 142 | this.defaultSeverity = defaultSeverity; 143 | } 144 | 145 | /** 146 | * Set the hostname or IP of the syslog server to which messages will be 147 | * sent. 148 | * 149 | * @param syslogServerHostname 150 | * The hostname or IP address of the syslog server. 151 | */ 152 | public abstract void setSyslogServerHostname(final String syslogServerHostname); 153 | 154 | /** 155 | * Set the port number of the syslog server to which messages will be sent. 156 | * 157 | * @param syslogServerPort 158 | * The port to which syslog messages will be sent. 159 | */ 160 | public abstract void setSyslogServerPort(int syslogServerPort); 161 | 162 | @Override 163 | public String toString() { 164 | return getClass().getName() + "{" + 165 | "defaultAppName='" + defaultAppName + '\'' + 166 | ", defaultFacility=" + defaultFacility + 167 | ", defaultMessageHostname='" + defaultMessageHostname + '\'' + 168 | ", defaultSeverity=" + defaultSeverity + 169 | ", messageFormat=" + messageFormat + 170 | ", sendCounter=" + sendCounter + 171 | ", sendDurationInNanosCounter=" + sendDurationInNanosCounter + 172 | ", sendErrorCounter=" + sendErrorCounter + 173 | '}'; 174 | } 175 | } 176 | -------------------------------------------------------------------------------- /src/main/java/com/cloudbees/syslog/sender/SyslogMessageSender.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2010-2014, CloudBees Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.cloudbees.syslog.sender; 17 | 18 | import com.cloudbees.syslog.SyslogMessage; 19 | import com.cloudbees.syslog.MessageFormat; 20 | 21 | import edu.umd.cs.findbugs.annotations.NonNull; 22 | import edu.umd.cs.findbugs.annotations.Nullable; 23 | import net.jcip.annotations.ThreadSafe; 24 | import java.io.CharArrayWriter; 25 | import java.io.Closeable; 26 | import java.io.IOException; 27 | import java.util.concurrent.TimeUnit; 28 | 29 | /** 30 | * Send messages to a Syslog server. 31 | * 32 | * Implementation MUST be thread safe. 33 | * 34 | * @author Cyrille Le Clerc 35 | */ 36 | @ThreadSafe 37 | public interface SyslogMessageSender extends Closeable { 38 | long DEFAULT_INET_ADDRESS_TTL_IN_MILLIS = TimeUnit.MILLISECONDS.convert(30, TimeUnit.SECONDS); 39 | long DEFAULT_INET_ADDRESS_TTL_IN_NANOS = TimeUnit.NANOSECONDS.convert(DEFAULT_INET_ADDRESS_TTL_IN_MILLIS, TimeUnit.MILLISECONDS); 40 | String DEFAULT_SYSLOG_HOST = "localhost"; 41 | MessageFormat DEFAULT_SYSLOG_MESSAGE_FORMAT = MessageFormat.RFC_3164; 42 | int DEFAULT_SYSLOG_PORT = 514; 43 | 44 | /** 45 | * Send the given message ; the Syslog fields (appName, severity, priority, hostname ...) are the default values 46 | * of the {@linkplain com.cloudbees.syslog.sender.SyslogMessageSender MessageSender}. 47 | * 48 | * @param message the message to send 49 | * @throws IOException 50 | */ 51 | void sendMessage(CharArrayWriter message) throws IOException; 52 | 53 | /** 54 | * Send the given message ; the Syslog fields (appName, severity, priority, hostname ...) are the default values 55 | * of the {@linkplain com.cloudbees.syslog.sender.SyslogMessageSender MessageSender}. 56 | * 57 | * @param message the message to send 58 | * @throws IOException 59 | */ 60 | void sendMessage(@Nullable CharSequence message) throws IOException; 61 | 62 | /** 63 | * Send the given {@link com.cloudbees.syslog.SyslogMessage}. 64 | * 65 | * @param message the message to send 66 | * @throws IOException 67 | */ 68 | void sendMessage(@NonNull SyslogMessage message) throws IOException; 69 | } 70 | -------------------------------------------------------------------------------- /src/main/java/com/cloudbees/syslog/sender/TcpSyslogMessageSender.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2010-2014, CloudBees Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.cloudbees.syslog.sender; 17 | 18 | import com.cloudbees.syslog.SyslogMessage; 19 | import com.cloudbees.syslog.util.CachingReference; 20 | import com.cloudbees.syslog.util.IoUtils; 21 | 22 | import edu.umd.cs.findbugs.annotations.NonNull; 23 | import edu.umd.cs.findbugs.annotations.Nullable; 24 | import net.jcip.annotations.ThreadSafe; 25 | import javax.net.SocketFactory; 26 | import javax.net.ssl.SSLContext; 27 | import javax.net.ssl.SSLSession; 28 | import javax.net.ssl.SSLSocket; 29 | import javax.net.ssl.SSLSocketFactory; 30 | import java.io.BufferedWriter; 31 | import java.io.Closeable; 32 | import java.io.IOException; 33 | import java.io.OutputStreamWriter; 34 | import java.io.Writer; 35 | import java.math.BigInteger; 36 | import java.net.ConnectException; 37 | import java.net.InetAddress; 38 | import java.net.InetSocketAddress; 39 | import java.net.Socket; 40 | import java.net.UnknownHostException; 41 | import java.nio.charset.StandardCharsets; 42 | import java.security.cert.Certificate; 43 | import java.security.cert.X509Certificate; 44 | import java.util.Objects; 45 | import java.util.concurrent.atomic.AtomicInteger; 46 | import java.util.logging.Level; 47 | 48 | /** 49 | * See RFC 6587 - Transmission of Syslog Messages over TCP 50 | * 51 | * @author Cyrille Le Clerc 52 | */ 53 | @ThreadSafe 54 | public class TcpSyslogMessageSender extends AbstractSyslogMessageSender implements Closeable { 55 | public final static int SETTING_SOCKET_CONNECT_TIMEOUT_IN_MILLIS_DEFAULT_VALUE = 500; 56 | public final static int SETTING_MAX_RETRY = 2; 57 | 58 | /** 59 | * {@link java.net.InetAddress InetAddress} of the remote Syslog Server. 60 | * 61 | * The {@code InetAddress} is refreshed regularly to handle DNS changes (default {@link #DEFAULT_INET_ADDRESS_TTL_IN_MILLIS}) 62 | * 63 | * Default value: {@link #DEFAULT_SYSLOG_HOST} 64 | */ 65 | protected CachingReference syslogServerHostnameReference; 66 | /** 67 | * Listen port of the remote Syslog server. 68 | * 69 | * Default: {@link #DEFAULT_SYSLOG_PORT} 70 | */ 71 | protected int syslogServerPort = DEFAULT_SYSLOG_PORT; 72 | 73 | private Socket socket; 74 | private Writer writer; 75 | private int socketConnectTimeoutInMillis = SETTING_SOCKET_CONNECT_TIMEOUT_IN_MILLIS_DEFAULT_VALUE; 76 | private boolean ssl; 77 | private SSLContext sslContext; 78 | /** 79 | * Number of retries to send a message before throwing an exception. 80 | */ 81 | private int maxRetryCount = SETTING_MAX_RETRY; 82 | /** 83 | * Number of exceptions trying to send message. 84 | */ 85 | protected final AtomicInteger trySendErrorCounter = new AtomicInteger(); 86 | 87 | // use the CR LF non transparent framing as described in "3.4.2. Non-Transparent-Framing" 88 | private String postfix = "\r\n"; 89 | 90 | @Override 91 | public synchronized void sendMessage(@NonNull SyslogMessage message) throws IOException { 92 | sendCounter.incrementAndGet(); 93 | long nanosBefore = System.nanoTime(); 94 | 95 | try { 96 | Exception lastException = null; 97 | for (int i = 0; i <= maxRetryCount; i++) { 98 | try { 99 | if (logger.isLoggable(Level.FINEST)) { 100 | logger.finest("Send syslog message " + message.toSyslogMessage(messageFormat)); 101 | } 102 | ensureSyslogServerConnection(); 103 | message.toSyslogMessage(messageFormat, writer); 104 | writer.write(postfix); 105 | writer.flush(); 106 | return; 107 | } catch (IOException | RuntimeException e) { 108 | lastException = e; 109 | IoUtils.closeQuietly(socket, writer); 110 | trySendErrorCounter.incrementAndGet(); 111 | } 112 | } 113 | if (lastException != null) { 114 | sendErrorCounter.incrementAndGet(); 115 | if (lastException instanceof IOException) { 116 | throw (IOException) lastException; 117 | } else if (lastException instanceof RuntimeException) { 118 | throw (RuntimeException) lastException; 119 | } 120 | } 121 | } finally { 122 | sendDurationInNanosCounter.addAndGet(System.nanoTime() - nanosBefore); 123 | } 124 | } 125 | 126 | private synchronized void ensureSyslogServerConnection() throws IOException { 127 | InetAddress inetAddress = syslogServerHostnameReference.get(); 128 | if (socket != null && !Objects.equals(socket.getInetAddress(), inetAddress)) { 129 | logger.info("InetAddress of the Syslog Server have changed, create a new connection. " + 130 | "Before=" + socket.getInetAddress() + ", new=" + inetAddress); 131 | IoUtils.closeQuietly(socket, writer); 132 | writer = null; 133 | socket = null; 134 | } 135 | boolean socketIsValid; 136 | try { 137 | socketIsValid = socket != null && 138 | socket.isConnected() 139 | && socket.isBound() 140 | && !socket.isClosed() 141 | && !socket.isInputShutdown() 142 | && !socket.isOutputShutdown(); 143 | } catch (Exception e) { 144 | socketIsValid = false; 145 | } 146 | if (!socketIsValid) { 147 | writer = null; 148 | try { 149 | if (ssl) { 150 | if (sslContext == null) { 151 | socket = SSLSocketFactory.getDefault().createSocket(); 152 | } else { 153 | socket = sslContext.getSocketFactory().createSocket(); 154 | } 155 | } else { 156 | socket = SocketFactory.getDefault().createSocket(); 157 | } 158 | socket.setKeepAlive(true); 159 | socket.connect( 160 | new InetSocketAddress(inetAddress, syslogServerPort), 161 | socketConnectTimeoutInMillis); 162 | 163 | if (socket instanceof SSLSocket && logger.isLoggable(Level.FINER)) { 164 | try { 165 | SSLSocket sslSocket = (SSLSocket) socket; 166 | SSLSession session = sslSocket.getSession(); 167 | logger.finer("The Certificates used by peer"); 168 | for (Certificate certificate : session.getPeerCertificates()) { 169 | if (certificate instanceof X509Certificate) { 170 | X509Certificate x509Certificate = (X509Certificate) certificate; 171 | logger.finer("" + x509Certificate.getSubjectDN()); 172 | } else { 173 | logger.finer("" + certificate); 174 | } 175 | } 176 | logger.finer("Peer host is " + session.getPeerHost()); 177 | logger.finer("Cipher is " + session.getCipherSuite()); 178 | logger.finer("Protocol is " + session.getProtocol()); 179 | logger.finer("ID is " + new BigInteger(session.getId())); 180 | logger.finer("Session created in " + session.getCreationTime()); 181 | logger.finer("Session accessed in " + session.getLastAccessedTime()); 182 | } catch (Exception e) { 183 | logger.warn("Exception dumping debug info for " + socket, e); 184 | } 185 | } 186 | } catch (IOException e) { 187 | ConnectException ce = new ConnectException("Exception connecting to " + inetAddress + ":" + syslogServerPort); 188 | ce.initCause(e); 189 | throw ce; 190 | } 191 | } 192 | if (writer == null) { 193 | writer = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream(), StandardCharsets.UTF_8)); 194 | } 195 | } 196 | 197 | @Override 198 | public void setSyslogServerHostname(final String syslogServerHostname) { 199 | this.syslogServerHostnameReference = new CachingReference(DEFAULT_INET_ADDRESS_TTL_IN_NANOS) { 200 | @Nullable 201 | @Override 202 | protected InetAddress newObject() { 203 | try { 204 | return InetAddress.getByName(syslogServerHostname); 205 | } catch (UnknownHostException e) { 206 | throw new IllegalStateException(e); 207 | } 208 | } 209 | }; 210 | } 211 | 212 | @Override 213 | public void setSyslogServerPort(int syslogServerPort) { 214 | this.syslogServerPort = syslogServerPort; 215 | } 216 | 217 | @Nullable 218 | public String getSyslogServerHostname() { 219 | if (syslogServerHostnameReference == null) 220 | return null; 221 | InetAddress inetAddress = syslogServerHostnameReference.get(); 222 | return inetAddress == null ? null : inetAddress.getHostName(); 223 | } 224 | 225 | public int getSyslogServerPort() { 226 | return syslogServerPort; 227 | } 228 | 229 | public boolean isSsl() { 230 | return ssl; 231 | } 232 | 233 | public void setSsl(boolean ssl) { 234 | this.ssl = ssl; 235 | } 236 | 237 | public synchronized void setSSLContext(SSLContext sslContext) { 238 | this.sslContext = sslContext; 239 | } 240 | 241 | public synchronized SSLContext getSSLContext() { 242 | return this.sslContext; 243 | } 244 | 245 | public int getSocketConnectTimeoutInMillis() { 246 | return socketConnectTimeoutInMillis; 247 | } 248 | 249 | public int getMaxRetryCount() { 250 | return maxRetryCount; 251 | } 252 | 253 | public int getTrySendErrorCounter() { 254 | return trySendErrorCounter.get(); 255 | } 256 | 257 | public void setSocketConnectTimeoutInMillis(int socketConnectTimeoutInMillis) { 258 | this.socketConnectTimeoutInMillis = socketConnectTimeoutInMillis; 259 | } 260 | 261 | public void setMaxRetryCount(int maxRetryCount) { 262 | this.maxRetryCount = maxRetryCount; 263 | } 264 | 265 | public synchronized void setPostfix(String postfix) { 266 | this.postfix = postfix; 267 | } 268 | 269 | @Override 270 | public String toString() { 271 | return getClass().getName() + "{" + 272 | "syslogServerHostname='" + this.getSyslogServerHostname() + '\'' + 273 | ", syslogServerPort='" + this.getSyslogServerPort() + '\'' + 274 | ", ssl=" + ssl + 275 | ", maxRetryCount=" + maxRetryCount + 276 | ", socketConnectTimeoutInMillis=" + socketConnectTimeoutInMillis + 277 | ", defaultAppName='" + defaultAppName + '\'' + 278 | ", defaultFacility=" + defaultFacility + 279 | ", defaultMessageHostname='" + defaultMessageHostname + '\'' + 280 | ", defaultSeverity=" + defaultSeverity + 281 | ", messageFormat=" + messageFormat + 282 | ", sendCounter=" + sendCounter + 283 | ", sendDurationInNanosCounter=" + sendDurationInNanosCounter + 284 | ", sendErrorCounter=" + sendErrorCounter + 285 | ", trySendErrorCounter=" + trySendErrorCounter + 286 | '}'; 287 | } 288 | 289 | @Override 290 | public void close() throws IOException { 291 | this.socket.close(); 292 | } 293 | } 294 | -------------------------------------------------------------------------------- /src/main/java/com/cloudbees/syslog/sender/UdpSyslogMessageSender.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2010-2014, CloudBees Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.cloudbees.syslog.sender; 17 | 18 | import com.cloudbees.syslog.SyslogMessage; 19 | import com.cloudbees.syslog.util.CachingReference; 20 | 21 | import edu.umd.cs.findbugs.annotations.Nullable; 22 | import net.jcip.annotations.ThreadSafe; 23 | import java.io.ByteArrayOutputStream; 24 | import java.io.Closeable; 25 | import java.io.IOException; 26 | import java.io.OutputStreamWriter; 27 | import java.io.Writer; 28 | import java.net.DatagramPacket; 29 | import java.net.DatagramSocket; 30 | import java.net.InetAddress; 31 | import java.net.UnknownHostException; 32 | import java.nio.charset.StandardCharsets; 33 | import java.util.logging.Level; 34 | 35 | /** 36 | * Syslog message sender over UDP. 37 | * 38 | * TODO optimize performances recycling the byte arrays. Note: {@link java.io.ByteArrayOutputStream} 39 | * can be subclassed to access to the underlying {@code byte[]}. 40 | * 41 | * @author Cyrille Le Clerc 42 | */ 43 | @ThreadSafe 44 | public class UdpSyslogMessageSender extends AbstractSyslogMessageSender implements Closeable { 45 | /** 46 | * {@link java.net.InetAddress InetAddress} of the remote Syslog Server. 47 | * 48 | * The {@code InetAddress} is refreshed regularly to handle DNS changes (default {@link #DEFAULT_INET_ADDRESS_TTL_IN_MILLIS}) 49 | * 50 | * Default value: {@link #DEFAULT_SYSLOG_HOST} 51 | */ 52 | protected CachingReference syslogServerHostnameReference; 53 | /** 54 | * Listen port of the remote Syslog server. 55 | * 56 | * Default: {@link #DEFAULT_SYSLOG_PORT} 57 | */ 58 | protected int syslogServerPort = DEFAULT_SYSLOG_PORT; 59 | 60 | private DatagramSocket datagramSocket; 61 | 62 | public UdpSyslogMessageSender() { 63 | try { 64 | setSyslogServerHostname(DEFAULT_SYSLOG_HOST); 65 | datagramSocket = new DatagramSocket(); 66 | } catch (IOException e) { 67 | throw new IllegalStateException("Exception initializing datagramSocket", e); 68 | } 69 | } 70 | 71 | /** 72 | * Send the given {@link com.cloudbees.syslog.SyslogMessage} over UDP. 73 | * 74 | * @param message the message to send 75 | * @throws IOException 76 | */ 77 | @Override 78 | public void sendMessage(SyslogMessage message) throws IOException { 79 | sendCounter.incrementAndGet(); 80 | long nanosBefore = System.nanoTime(); 81 | 82 | try { 83 | ByteArrayOutputStream baos = new ByteArrayOutputStream(); 84 | Writer out = new OutputStreamWriter(baos, StandardCharsets.UTF_8); 85 | message.toSyslogMessage(messageFormat, out); 86 | out.flush(); 87 | 88 | if (logger.isLoggable(Level.FINEST)) { 89 | logger.finest("Send syslog message " + new String(baos.toByteArray(), StandardCharsets.UTF_8)); 90 | } 91 | byte[] bytes = baos.toByteArray(); 92 | 93 | DatagramPacket packet = new DatagramPacket(bytes, bytes.length, syslogServerHostnameReference.get(), syslogServerPort); 94 | datagramSocket.send(packet); 95 | } catch (IOException | RuntimeException e) { 96 | sendErrorCounter.incrementAndGet(); 97 | throw e; 98 | } finally { 99 | sendDurationInNanosCounter.addAndGet(System.nanoTime() - nanosBefore); 100 | } 101 | } 102 | 103 | 104 | @Override 105 | public void setSyslogServerHostname(final String syslogServerHostname) { 106 | this.syslogServerHostnameReference = new CachingReference(DEFAULT_INET_ADDRESS_TTL_IN_NANOS) { 107 | @Nullable 108 | @Override 109 | protected InetAddress newObject() { 110 | try { 111 | return InetAddress.getByName(syslogServerHostname); 112 | } catch (UnknownHostException e) { 113 | throw new IllegalStateException(e); 114 | } 115 | } 116 | }; 117 | } 118 | 119 | @Override 120 | public void setSyslogServerPort(int syslogServerPort) { 121 | this.syslogServerPort = syslogServerPort; 122 | } 123 | 124 | @Nullable 125 | public String getSyslogServerHostname() { 126 | InetAddress inetAddress = syslogServerHostnameReference.get(); 127 | return inetAddress == null ? null : inetAddress.getHostName(); 128 | } 129 | 130 | public int getSyslogServerPort() { 131 | return syslogServerPort; 132 | } 133 | 134 | @Override 135 | public String toString() { 136 | return getClass().getName() + "{" + 137 | "syslogServerHostname='" + this.getSyslogServerHostname() + '\'' + 138 | ", syslogServerPort='" + this.getSyslogServerPort() + '\'' + 139 | ", defaultAppName='" + defaultAppName + '\'' + 140 | ", defaultFacility=" + defaultFacility + 141 | ", defaultMessageHostname='" + defaultMessageHostname + '\'' + 142 | ", defaultSeverity=" + defaultSeverity + 143 | ", messageFormat=" + messageFormat + 144 | ", sendCounter=" + sendCounter + 145 | ", sendDurationInNanosCounter=" + sendDurationInNanosCounter + 146 | ", sendErrorCounter=" + sendErrorCounter + 147 | '}'; 148 | } 149 | 150 | @Override 151 | public void close() throws IOException { 152 | this.datagramSocket.close(); 153 | } 154 | } 155 | -------------------------------------------------------------------------------- /src/main/java/com/cloudbees/syslog/util/CachingReference.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2010-2013, CloudBees Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.cloudbees.syslog.util; 17 | 18 | import edu.umd.cs.findbugs.annotations.Nullable; 19 | import java.util.concurrent.TimeUnit; 20 | import java.util.concurrent.locks.ReadWriteLock; 21 | import java.util.concurrent.locks.ReentrantReadWriteLock; 22 | 23 | /** 24 | * Maintains a cached version of the {@code Object} that it holds and handle the renewal of this object upon expiration. 25 | * 26 | * Greatly inspired by the {@code CachedData} sample provided in the javadoc 27 | * of {@link java.util.concurrent.locks.ReentrantReadWriteLock}. 28 | * 29 | * {@code Object} is created implementing the {@link #newObject()} method. 30 | * 31 | * 32 | * Sample to get an {@code InetAddress} refreshed against a DNS every 10 seconds: 33 | *

 34 |  * CachingReference myRemoteServerAddress = new CachingReference<InetAddress>(10, TimeUnit.SECONDS) {
 35 |  *     protected InetAddress newObject() {
 36 |  *         try {
 37 |  *             return InetAddress.getByName(myRemoteServerHostname);
 38 |  *         } catch () {
 39 |  *             throw new RuntimeException("Exception resolving '" + myRemoteServerHostname + "'", e);
 40 |  *         }
 41 |  *     }
 42 |  * }
 43 |  * 
44 | * 45 | * @author Cyrille Le Clerc 46 | */ 47 | public abstract class CachingReference { 48 | private final ReadWriteLock rwl = new ReentrantReadWriteLock(); 49 | private long lastCreationInNanos; 50 | private long timeToLiveInNanos; 51 | private E object; 52 | 53 | public CachingReference(long timeToLiveInNanos) { 54 | this.timeToLiveInNanos = timeToLiveInNanos; 55 | } 56 | 57 | public CachingReference(long timeToLive, TimeUnit timeToLiveUnit) { 58 | this(TimeUnit.NANOSECONDS.convert(timeToLive, timeToLiveUnit)); 59 | } 60 | 61 | /** 62 | * @return the newly created object. 63 | */ 64 | @Nullable 65 | protected abstract E newObject(); 66 | 67 | /** 68 | * @return the up to date version of the {@code Object} hold by this reference. 69 | */ 70 | @Nullable 71 | public E get() { 72 | rwl.readLock().lock(); 73 | try { 74 | if ((System.nanoTime() - lastCreationInNanos) > timeToLiveInNanos) { 75 | // Must release read lock before acquiring write lock 76 | rwl.readLock().unlock(); 77 | rwl.writeLock().lock(); 78 | try { 79 | // Recheck state because another thread might have 80 | // acquired write lock and changed state before we did. 81 | if ((System.nanoTime() - lastCreationInNanos) > timeToLiveInNanos) { 82 | object = newObject(); 83 | lastCreationInNanos = System.nanoTime(); 84 | } 85 | } finally { 86 | // Downgrade by acquiring read lock before releasing write lock 87 | rwl.readLock().lock(); 88 | rwl.writeLock().unlock(); 89 | } 90 | } 91 | return object; 92 | } finally { 93 | rwl.readLock().unlock(); 94 | } 95 | } 96 | 97 | @Override 98 | public String toString() { 99 | return "CachingReference[" + this.object + "]"; 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /src/main/java/com/cloudbees/syslog/util/ConcurrentDateFormat.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2010-2014, CloudBees Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.cloudbees.syslog.util; 17 | 18 | import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; 19 | 20 | import edu.umd.cs.findbugs.annotations.NonNull; 21 | import java.text.SimpleDateFormat; 22 | import java.util.Date; 23 | import java.util.Locale; 24 | import java.util.TimeZone; 25 | import java.util.concurrent.BlockingQueue; 26 | import java.util.concurrent.LinkedBlockingDeque; 27 | 28 | /** 29 | * Thread safe date formatter. 30 | * 31 | * @author Cyrille Le Clerc 32 | */ 33 | public class ConcurrentDateFormat { 34 | private final BlockingQueue dateFormats; 35 | private final String pattern; 36 | private final Locale locale; 37 | private final TimeZone timeZone; 38 | 39 | /** 40 | * Note: This constructor may not support all locales. 41 | * For full coverage, use the factory methods in the {@link java.text.DateFormat} 42 | * class. 43 | * 44 | * @param pattern the pattern describing the date and time pattern 45 | * @param locale the locale whose date pattern symbols should be used 46 | * @param timeZone the timezone used by the underlying calendar 47 | * @param maxCacheSize 48 | * @throws NullPointerException if the given pattern or locale is null 49 | * @throws IllegalArgumentException if the given pattern is invalid 50 | */ 51 | public ConcurrentDateFormat(String pattern, Locale locale, TimeZone timeZone, int maxCacheSize) { 52 | this.dateFormats = new LinkedBlockingDeque<>(maxCacheSize); 53 | this.pattern = pattern; 54 | this.locale = locale; 55 | this.timeZone = timeZone; 56 | } 57 | 58 | /** 59 | * Formats a Date into a date/time string. 60 | * 61 | * @param date the time value to be formatted into a time string. 62 | * @return the formatted time string. 63 | */ 64 | @NonNull 65 | @SuppressFBWarnings("RV_RETURN_VALUE_IGNORED_BAD_PRACTICE") 66 | public String format(@NonNull Date date) { 67 | SimpleDateFormat dateFormat = dateFormats.poll(); 68 | if (dateFormat == null) { 69 | dateFormat = new SimpleDateFormat(pattern, locale); 70 | dateFormat.setTimeZone(timeZone); 71 | } 72 | try { 73 | return dateFormat.format(date); 74 | } finally { 75 | dateFormats.offer(dateFormat); 76 | } 77 | } 78 | 79 | @Override 80 | public String toString() { 81 | return "ConcurrentDateFormat[pattern=" + pattern + "]"; 82 | } 83 | } -------------------------------------------------------------------------------- /src/main/java/com/cloudbees/syslog/util/InternalLogger.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2010-2014, CloudBees Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.cloudbees.syslog.util; 17 | 18 | import com.cloudbees.syslog.integration.jul.util.LevelHelper; 19 | 20 | import edu.umd.cs.findbugs.annotations.NonNull; 21 | import edu.umd.cs.findbugs.annotations.Nullable; 22 | import java.text.DateFormat; 23 | import java.text.SimpleDateFormat; 24 | import java.util.Date; 25 | import java.util.logging.Level; 26 | import java.util.logging.Logger; 27 | 28 | /** 29 | * Don't use {@link java.util.logging.Logger} as this code can be used as an Handler for java.util.logging and we would then have an infinite loop. 30 | * 31 | * @author Cyrille Le Clerc 32 | */ 33 | public class InternalLogger { 34 | 35 | private static Level level; 36 | 37 | static { 38 | try { 39 | level = LevelHelper.findLevel(System.getProperty("com.cloudbees.syslog.debugLevel")); 40 | } catch (RuntimeException e) { 41 | e.printStackTrace(); 42 | } 43 | } 44 | 45 | public static InternalLogger getLogger(@NonNull String name) { 46 | return new InternalLogger(name); 47 | } 48 | 49 | public static InternalLogger getLogger(@NonNull Class clazz) { 50 | return getLogger(clazz.getName()); 51 | } 52 | 53 | public static Level getLevel() { 54 | return level; 55 | } 56 | 57 | public static void setLevel(Level level) { 58 | InternalLogger.level = level; 59 | } 60 | 61 | private DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss:SSS"); 62 | private final String name; 63 | /** 64 | * use java.util.logger to find the logger level if not specified by system property. 65 | */ 66 | private final Logger julLogger; 67 | 68 | public InternalLogger(String name) { 69 | this.name = name; 70 | this.julLogger = Logger.getLogger(name); 71 | } 72 | 73 | 74 | public boolean isLoggable(Level level) { 75 | if (level == null) 76 | return false; 77 | 78 | if (this.level == null) 79 | return julLogger.isLoggable(level); 80 | 81 | return level.intValue() >= this.level.intValue(); 82 | } 83 | 84 | public void finest(@Nullable String msg) { 85 | log(Level.FINEST, msg); 86 | } 87 | 88 | public void fine(@Nullable String msg) { 89 | log(Level.FINE, msg); 90 | } 91 | 92 | public void finer(@Nullable String msg) { 93 | log(Level.FINER, msg); 94 | } 95 | 96 | public void info(@Nullable String msg) { 97 | log(Level.INFO, msg); 98 | } 99 | 100 | public void log(@Nullable Level level, @Nullable String msg) { 101 | log(level, msg, null); 102 | } 103 | 104 | public void warn(@Nullable String msg) { 105 | log(Level.WARNING, msg); 106 | } 107 | 108 | public void warn(@Nullable String msg, @Nullable Throwable t) { 109 | log(Level.WARNING, msg, t); 110 | } 111 | 112 | /** 113 | * synchronize for the {@link java.text.SimpleDateFormat}. 114 | * 115 | * @param level 116 | * @param msg 117 | * @param t 118 | */ 119 | public synchronized void log(@Nullable Level level, @Nullable String msg, @Nullable Throwable t) { 120 | if (!isLoggable(level)) 121 | return; 122 | System.err.println(df.format(new Date()) + " [" + Thread.currentThread().getName() + "] " + name + " - " + level.getName() + ": " + msg); 123 | if (t != null) 124 | t.printStackTrace(); 125 | 126 | } 127 | 128 | } 129 | -------------------------------------------------------------------------------- /src/main/java/com/cloudbees/syslog/util/IoUtils.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2010-2014, CloudBees Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.cloudbees.syslog.util; 17 | 18 | import edu.umd.cs.findbugs.annotations.Nullable; 19 | import java.io.IOException; 20 | import java.io.Writer; 21 | import java.net.Socket; 22 | 23 | /** 24 | * @author Cyrille Le Clerc 25 | */ 26 | public class IoUtils { 27 | private IoUtils() { 28 | 29 | } 30 | 31 | public static void closeQuietly(@Nullable Socket socket) { 32 | try { 33 | if (socket != null && !socket.isClosed()) { 34 | socket.close(); 35 | } 36 | } catch (Exception e) { 37 | } 38 | } 39 | 40 | /** 41 | * Note: does not {@link java.io.Writer#flush()} before closing. 42 | * 43 | * @param socket 44 | * @param writer 45 | */ 46 | public static void closeQuietly(@Nullable Socket socket, @Nullable Writer writer) { 47 | if (writer != null) { 48 | try { 49 | writer.close(); 50 | } catch (IOException e) { 51 | 52 | } 53 | } 54 | closeQuietly(socket); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/test/java/com/cloudbees/syslog/SyslogMessageTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2010-2013, CloudBees Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.cloudbees.syslog; 17 | 18 | import java.util.Calendar; 19 | import java.util.TimeZone; 20 | 21 | import org.junit.Test; 22 | 23 | import static org.hamcrest.Matchers.is; 24 | import static org.hamcrest.MatcherAssert.assertThat; 25 | 26 | /** 27 | * @author Cyrille Le Clerc 28 | */ 29 | public class SyslogMessageTest { 30 | 31 | @Test 32 | public void testRfc5425Format() { 33 | // GIVEN 34 | Calendar cal = Calendar.getInstance(); 35 | cal.setTimeZone(TimeZone.getTimeZone("GMT")); 36 | cal.set(2013, Calendar.DECEMBER, 5, 10, 30, 5); 37 | cal.set(Calendar.MILLISECOND, 0); 38 | 39 | System.out.println(SyslogMessage.rfc3339DateFormat.format(cal.getTime())); 40 | System.out.println(cal.getTimeInMillis()); 41 | 42 | 43 | SyslogMessage message = new SyslogMessage() 44 | .withTimestamp(cal.getTimeInMillis()) 45 | .withAppName("my_app") 46 | .withHostname("myserver.example.com") 47 | .withFacility(Facility.USER) 48 | .withSeverity(Severity.INFORMATIONAL) 49 | .withTimestamp(cal.getTimeInMillis()) 50 | .withMsg("a syslog message"); 51 | 52 | // WHEN 53 | String actual = message.toRfc5425SyslogMessage(); 54 | 55 | // THEN 56 | String expected = "81 <14>1 2013-12-05T10:30:05.000Z myserver.example.com my_app - - - a syslog message"; 57 | assertThat(actual, is(expected)); 58 | } 59 | 60 | @Test 61 | public void testRfc5424Format() { 62 | 63 | Calendar cal = Calendar.getInstance(); 64 | cal.setTimeZone(TimeZone.getTimeZone("GMT")); 65 | cal.set(2013, Calendar.DECEMBER, 5, 10, 30, 5); 66 | cal.set(Calendar.MILLISECOND, 0); 67 | 68 | System.out.println(SyslogMessage.rfc3339DateFormat.format(cal.getTime())); 69 | System.out.println(cal.getTimeInMillis()); 70 | 71 | 72 | SyslogMessage message = new SyslogMessage() 73 | .withTimestamp(cal.getTimeInMillis()) 74 | .withAppName("my_app") 75 | .withHostname("myserver.example.com") 76 | .withFacility(Facility.USER) 77 | .withSeverity(Severity.INFORMATIONAL) 78 | .withTimestamp(cal.getTimeInMillis()) 79 | .withMsg("a syslog message"); 80 | 81 | String actual = message.toRfc5424SyslogMessage(); 82 | String expected = "<14>1 2013-12-05T10:30:05.000Z myserver.example.com my_app - - - a syslog message"; 83 | 84 | assertThat(actual, is(expected)); 85 | 86 | } 87 | 88 | @Test 89 | public void testRfc5424FormatWithStructuredData() { 90 | Calendar cal = Calendar.getInstance(); 91 | cal.setTimeZone(TimeZone.getTimeZone("GMT")); 92 | cal.set(2013, Calendar.DECEMBER, 5, 10, 30, 5); 93 | cal.set(Calendar.MILLISECOND, 0); 94 | 95 | System.out.println(SyslogMessage.rfc3339DateFormat.format(cal.getTime())); 96 | System.out.println(cal.getTimeInMillis()); 97 | 98 | 99 | SyslogMessage message = new SyslogMessage() 100 | .withTimestamp(cal.getTimeInMillis()) 101 | .withAppName("my_app") 102 | .withHostname("myserver.example.com") 103 | .withFacility(Facility.USER) 104 | .withSeverity(Severity.INFORMATIONAL) 105 | .withTimestamp(cal.getTimeInMillis()) 106 | .withMsg("a syslog message") 107 | .withSDElement(new SDElement("exampleSDID@32473", new SDParam("iut", "3"), new SDParam("eventSource", "Application"), new SDParam("eventID", "1011"))); 108 | 109 | String actual = message.toRfc5424SyslogMessage(); 110 | String expected = "<14>1 2013-12-05T10:30:05.000Z myserver.example.com my_app - - [exampleSDID@32473 iut=\"3\" eventSource=\"Application\" eventID=\"1011\"] a syslog message"; 111 | 112 | assertThat(actual, is(expected)); 113 | 114 | message.withSDElement(new SDElement("examplePriority@32473", new SDParam("class", "high"))); 115 | actual = message.toRfc5424SyslogMessage(); 116 | expected = "<14>1 2013-12-05T10:30:05.000Z myserver.example.com my_app - - [exampleSDID@32473 iut=\"3\" eventSource=\"Application\" eventID=\"1011\"][examplePriority@32473 class=\"high\"] a syslog message"; 117 | 118 | assertThat(actual, is(expected)); 119 | } 120 | 121 | @Test 122 | public void testRfc3164Format() { 123 | 124 | Calendar cal = Calendar.getInstance(); 125 | cal.setTimeZone(TimeZone.getDefault()); 126 | cal.set(2013, Calendar.DECEMBER, 5, 10, 30, 5); 127 | cal.set(Calendar.MILLISECOND, 0); 128 | 129 | System.out.println(SyslogMessage.rfc3339DateFormat.format(cal.getTime())); 130 | System.out.println(cal.getTimeInMillis()); 131 | 132 | 133 | SyslogMessage message = new SyslogMessage() 134 | .withTimestamp(cal.getTimeInMillis()) 135 | .withAppName("my_app") 136 | .withHostname("myserver.example.com") 137 | .withFacility(Facility.USER) 138 | .withSeverity(Severity.INFORMATIONAL) 139 | .withTimestamp(cal.getTimeInMillis()) 140 | .withMsg("a syslog message"); 141 | 142 | String actual = message.toRfc3164SyslogMessage(); 143 | String expected = "<14>Dec 05 10:30:05 myserver.example.com my_app: a syslog message"; 144 | 145 | assertThat(actual, is(expected)); 146 | 147 | } 148 | } 149 | -------------------------------------------------------------------------------- /src/test/java/com/cloudbees/syslog/integration/jul/SyslogHandlerTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2010-2013 the original author or authors 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining 5 | * a copy of this software and associated documentation files (the 6 | * "Software"), to deal in the Software without restriction, including 7 | * without limitation the rights to use, copy, modify, merge, publish, 8 | * distribute, sublicense, and/or sell copies of the Software, and to 9 | * permit persons to whom the Software is furnished to do so, subject to 10 | * the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be 13 | * included in all copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 19 | * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 20 | * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 21 | * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | * 23 | */ 24 | package com.cloudbees.syslog.integration.jul; 25 | 26 | import com.cloudbees.syslog.sender.UdpSyslogMessageSender; 27 | import org.junit.Test; 28 | 29 | import java.util.logging.Level; 30 | import java.util.logging.Logger; 31 | 32 | /** 33 | * @author Cyrille Le Clerc 34 | */ 35 | public class SyslogHandlerTest { 36 | 37 | @Test 38 | public void test(){ 39 | Logger logger = Logger.getLogger(getClass().getName()); 40 | logger.setLevel(Level.FINEST); 41 | 42 | UdpSyslogMessageSender messageSender = new UdpSyslogMessageSender(); 43 | SyslogHandler syslogHandler = new SyslogHandler(messageSender, Level.ALL, null); 44 | 45 | messageSender.setSyslogServerHostname("cloudbees1.papertrailapp.com"); 46 | messageSender.setSyslogServerPort(18977); 47 | 48 | syslogHandler.setMessageHostname("mysecretkey"); 49 | syslogHandler.setAppName("SyslogHandlerTest"); 50 | logger.addHandler(syslogHandler); 51 | 52 | logger.fine("hello world 2"); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/test/java/com/cloudbees/syslog/sender/TcpSyslogMessageSenderLoadTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2010-2014, CloudBees Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.cloudbees.syslog.sender; 17 | 18 | import com.cloudbees.syslog.Facility; 19 | import com.cloudbees.syslog.Severity; 20 | 21 | import java.io.IOException; 22 | import java.util.Random; 23 | import java.util.concurrent.ExecutorService; 24 | import java.util.concurrent.Executors; 25 | import java.util.concurrent.TimeUnit; 26 | import java.util.concurrent.atomic.AtomicInteger; 27 | 28 | /** 29 | * @author Cyrille Le Clerc 30 | */ 31 | public class TcpSyslogMessageSenderLoadTest { 32 | 33 | public static void main(String[] args) throws Exception { 34 | final int THREADS_COUNT = 5; 35 | final int ITERATION_COUNT = 100; 36 | 37 | ExecutorService executorService = Executors.newFixedThreadPool(THREADS_COUNT); 38 | 39 | final TcpSyslogMessageSender messageSender = new TcpSyslogMessageSender(); 40 | messageSender.setDefaultMessageHostname("mysecretkey"); 41 | messageSender.setDefaultAppName("myapp"); 42 | messageSender.setDefaultFacility(Facility.USER); 43 | messageSender.setDefaultSeverity(Severity.INFORMATIONAL); 44 | messageSender.setSyslogServerHostname("logs2.papertrailapp.com"); 45 | // messageSender.setSyslogServerHostname("127.0.0.1"); 46 | messageSender.setSyslogServerPort(46022); 47 | messageSender.setSsl(true); 48 | 49 | final AtomicInteger count = new AtomicInteger(); 50 | 51 | final Random random = new Random(); 52 | 53 | for (int i = 0; i < THREADS_COUNT; i++) { 54 | final String prefix = "thread-" + i + "msg-"; 55 | 56 | Runnable command = new Runnable() { 57 | @Override 58 | public void run() { 59 | for (int j = 0; j < ITERATION_COUNT; j++) { 60 | try { 61 | messageSender.sendMessage(prefix + j); 62 | Thread.sleep(random.nextInt(3)); 63 | } catch (IOException | InterruptedException e) { 64 | System.err.println("ERROR in " + prefix); 65 | e.printStackTrace(); 66 | break; 67 | } 68 | } 69 | } 70 | }; 71 | 72 | executorService.execute(command); 73 | } 74 | 75 | executorService.shutdown(); 76 | executorService.awaitTermination(1, TimeUnit.MINUTES); 77 | System.out.println("sent " + messageSender.getSendCount() + " in " + messageSender.getSendDurationInMillis() + "ms"); 78 | System.out.println("bye"); 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /src/test/java/com/cloudbees/syslog/sender/TcpSyslogMessageSenderTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2010-2013, CloudBees Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.cloudbees.syslog.sender; 17 | 18 | import com.cloudbees.syslog.Facility; 19 | import com.cloudbees.syslog.MessageFormat; 20 | import com.cloudbees.syslog.Severity; 21 | import com.cloudbees.syslog.SyslogMessage; 22 | import org.junit.Ignore; 23 | import org.junit.Test; 24 | 25 | import java.sql.Timestamp; 26 | 27 | /** 28 | * @author Cyrille Le Clerc 29 | */ 30 | public class TcpSyslogMessageSenderTest { 31 | 32 | // @Ignore 33 | @Test 34 | public void send() throws Exception { 35 | TcpSyslogMessageSender messageSender = new TcpSyslogMessageSender(); 36 | messageSender.setDefaultMessageHostname("mysecretkey"); 37 | messageSender.setDefaultAppName("myapp"); 38 | messageSender.setDefaultFacility(Facility.USER); 39 | messageSender.setDefaultSeverity(Severity.INFORMATIONAL); 40 | messageSender.setSyslogServerHostname("logs2.papertrailapp.com"); 41 | messageSender.setSyslogServerPort(46022); 42 | messageSender.setMessageFormat(MessageFormat.RFC_3164); 43 | messageSender.setSsl(true); 44 | messageSender.sendMessage("unit test message over tcp éèà " + getClass() + " - " + new Timestamp(System.currentTimeMillis())); 45 | } 46 | 47 | @Ignore 48 | @Test 49 | public void send2() throws Exception { 50 | 51 | SyslogMessage msg = new SyslogMessage() 52 | .withAppName("my-app") 53 | .withFacility(Facility.USER) 54 | .withHostname("my-hostname") 55 | .withMsg("my message over tcp éèà " + new Timestamp(System.currentTimeMillis())) 56 | .withSeverity(Severity.INFORMATIONAL) 57 | .withTimestamp(System.currentTimeMillis()); 58 | 59 | TcpSyslogMessageSender messageSender = new TcpSyslogMessageSender(); 60 | messageSender.setSyslogServerHostname("logs2.papertrailapp.com"); 61 | messageSender.setSyslogServerPort(46022); 62 | messageSender.setMessageFormat(MessageFormat.RFC_3164); 63 | messageSender.setSsl(true); 64 | 65 | System.out.println(msg.toSyslogMessage(messageSender.getMessageFormat())); 66 | 67 | messageSender.sendMessage(msg); 68 | } 69 | 70 | 71 | @Ignore 72 | @Test 73 | public void sendOverSSL() throws Exception { 74 | 75 | SyslogMessage msg = new SyslogMessage() 76 | .withAppName("my-app") 77 | .withFacility(Facility.USER) 78 | .withHostname("my-hostname") 79 | .withMsg("my message over tcp ssl éèà " + new Timestamp(System.currentTimeMillis())) 80 | .withSeverity(Severity.INFORMATIONAL) 81 | .withTimestamp(System.currentTimeMillis()); 82 | 83 | TcpSyslogMessageSender messageSender = new TcpSyslogMessageSender(); 84 | messageSender.setSyslogServerHostname("logs2.papertrailapp.com"); 85 | messageSender.setSyslogServerPort(46022); 86 | messageSender.setMessageFormat(MessageFormat.RFC_3164); 87 | messageSender.setSsl(true); 88 | 89 | System.out.println(msg.toSyslogMessage(messageSender.getMessageFormat())); 90 | 91 | messageSender.sendMessage(msg); 92 | } 93 | 94 | 95 | /** 96 | * https://github.com/CloudBees-community/syslog-java-client/issues/19 97 | */ 98 | @Test 99 | public void test_bug19_NullPointerException_In_ToString(){ 100 | TcpSyslogMessageSender tcpSyslogMessageSender = new TcpSyslogMessageSender(); 101 | tcpSyslogMessageSender.toString(); 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /src/test/java/com/cloudbees/syslog/sender/UdpSyslogMessageSenderLoadTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2010-2014, CloudBees Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.cloudbees.syslog.sender; 17 | 18 | import com.cloudbees.syslog.Facility; 19 | import com.cloudbees.syslog.Severity; 20 | 21 | import java.io.IOException; 22 | import java.util.concurrent.ExecutorService; 23 | import java.util.concurrent.Executors; 24 | import java.util.concurrent.TimeUnit; 25 | import java.util.concurrent.atomic.AtomicInteger; 26 | 27 | /** 28 | * @author Cyrille Le Clerc 29 | */ 30 | public class UdpSyslogMessageSenderLoadTest { 31 | 32 | public static void main(String[] args) throws Exception { 33 | final int THREADS_COUNT = 10; 34 | final int ITERATION_COUNT = 1000; 35 | 36 | ExecutorService executorService = Executors.newFixedThreadPool(THREADS_COUNT); 37 | 38 | final UdpSyslogMessageSender messageSender = new UdpSyslogMessageSender(); 39 | messageSender.setDefaultMessageHostname("mysecretkey"); 40 | messageSender.setDefaultAppName("myapp"); 41 | messageSender.setDefaultFacility(Facility.USER); 42 | messageSender.setDefaultSeverity(Severity.INFORMATIONAL); 43 | messageSender.setSyslogServerHostname("logs2.papertrailapp.com"); 44 | // messageSender.setSyslogServerHostname("127.0.0.1"); 45 | messageSender.setSyslogServerPort(46022); 46 | 47 | final AtomicInteger count = new AtomicInteger(); 48 | 49 | 50 | for (int i = 0; i < THREADS_COUNT; i++) { 51 | final String prefix = "thread-" + i + "-udp-msg-"; 52 | 53 | Runnable command = new Runnable() { 54 | @Override 55 | public void run() { 56 | for (int j = 0; j < ITERATION_COUNT; j++) { 57 | try { 58 | messageSender.sendMessage(prefix + j); 59 | } catch (IOException e) { 60 | System.err.println("ERROR in " + prefix); 61 | e.printStackTrace(); 62 | break; 63 | } 64 | } 65 | } 66 | }; 67 | 68 | executorService.execute(command); 69 | } 70 | 71 | executorService.shutdown(); 72 | executorService.awaitTermination(1, TimeUnit.MINUTES); 73 | System.out.println("sent " + messageSender.getSendCount() + " in " + messageSender.getSendDurationInMillis() + "ms"); 74 | System.out.println("bye"); 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /src/test/java/com/cloudbees/syslog/sender/UpdSyslogMessageSenderTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2010-2013, CloudBees Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.cloudbees.syslog.sender; 17 | 18 | import com.cloudbees.syslog.Facility; 19 | import com.cloudbees.syslog.Severity; 20 | import org.junit.Test; 21 | 22 | import java.sql.Timestamp; 23 | 24 | /** 25 | * @author Cyrille Le Clerc 26 | */ 27 | public class UpdSyslogMessageSenderTest { 28 | 29 | // @Ignore 30 | @Test 31 | public void send() throws Exception { 32 | UdpSyslogMessageSender messageSender = new UdpSyslogMessageSender(); 33 | messageSender.setDefaultMessageHostname("mysecretkey"); 34 | messageSender.setDefaultAppName("myapp"); 35 | messageSender.setDefaultFacility(Facility.USER); 36 | messageSender.setDefaultSeverity(Severity.INFORMATIONAL); 37 | // messageSender.setSyslogServerHostname("cloudbees1.papertrailapp.com"); 38 | messageSender.setSyslogServerHostname("127.0.0.1"); 39 | messageSender.setSyslogServerPort(18977); 40 | messageSender.sendMessage("unit test message éèà " + getClass() + " - " + new Timestamp(System.currentTimeMillis())); 41 | } 42 | 43 | 44 | } 45 | -------------------------------------------------------------------------------- /src/test/java/com/cloudbees/syslog/util/CachingReferenceTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2010-2013, CloudBees Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.cloudbees.syslog.util; 17 | 18 | import org.hamcrest.Matchers; 19 | import org.junit.Test; 20 | 21 | import edu.umd.cs.findbugs.annotations.Nullable; 22 | import java.util.concurrent.TimeUnit; 23 | 24 | import static org.hamcrest.MatcherAssert.assertThat; 25 | 26 | public class CachingReferenceTest { 27 | /** 28 | * Test that the locks are properly released. 29 | */ 30 | @Test 31 | public void test_return_value() { 32 | 33 | CachingReference cachingReference = new CachingReference(5, TimeUnit.SECONDS) { 34 | @Nullable 35 | @Override 36 | protected String newObject() { 37 | return "value"; 38 | } 39 | }; 40 | 41 | String actual = cachingReference.get(); 42 | assertThat(actual, Matchers.equalTo("value")); 43 | } 44 | 45 | /** 46 | * Test that the locks are properly released. 47 | */ 48 | @Test(expected = MyRuntimeException.class) 49 | public void test_throw_exception_in_get_object() { 50 | 51 | CachingReference cachingReference = new CachingReference(5, TimeUnit.SECONDS) { 52 | @Nullable 53 | @Override 54 | protected String newObject() { 55 | throw new MyRuntimeException(); 56 | } 57 | }; 58 | 59 | cachingReference.get(); 60 | } 61 | 62 | 63 | private static class MyRuntimeException extends RuntimeException { 64 | public MyRuntimeException() { 65 | super(); 66 | } 67 | 68 | public MyRuntimeException(Throwable cause) { 69 | super(cause); 70 | } 71 | 72 | public MyRuntimeException(String message) { 73 | super(message); 74 | } 75 | 76 | public MyRuntimeException(String message, Throwable cause) { 77 | super(message, cause); 78 | } 79 | 80 | protected MyRuntimeException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) { 81 | super(message, cause, enableSuppression, writableStackTrace); 82 | } 83 | } 84 | } --------------------------------------------------------------------------------