diff --git a/doc/aix-errlogger.md b/doc/aix-errlogger.md index bb6ab6c..bdb83fb 100644 --- a/doc/aix-errlogger.md +++ b/doc/aix-errlogger.md @@ -26,7 +26,7 @@ Add the following to the /etc/syslog.conf file: *.warn /var/log/error.log rotate time 1d files 7 # Optionally log authentication messages to remote host -#auth.info,authpriv.info @10.32.64.29 +#auth.info,authpriv.info @10.32.64.1 ``` We use *10.32.64.1* as our remote syslog server in the above example. diff --git a/doc/power-hmc.md b/doc/power-hmc.md index 83b1396..6e3f3d7 100644 --- a/doc/power-hmc.md +++ b/doc/power-hmc.md @@ -9,10 +9,10 @@ More information about HMC logging is available on the IBM [knowledge center](ht Network / Firewall must allow UDP (and possible TCP) traffic on port 514 from HMC to the remote syslog server. We use *10.32.64.1* as our remote syslog server in the example below. -To add a remote logging destination: +To add a remote logging destination, run the following command. Use the filter to discard unwanted messaged. ```shell -chhmc -c syslog -t udp -s add -h 10.32.64.1 --input "filter_msg_contains_discard_strings=run-parts,slice,session,leases,renewal,0anacron,Session,DHCPREQUEST,DHCPACK,CMD" +chhmc -c syslog -t udp -s add -h 10.32.64.1 --input "filter_msg_contains_discard_strings=run-parts,slice,session,leases,renewal,0anacron,Session,DHCPREQUEST,DHCPACK,CMD,CRON" ``` In the above example we filter away some messages that we are not interested in forwarding on remotely. diff --git a/doc/powervc-auth.md b/doc/powervc-auth.md new file mode 100644 index 0000000..9914ebd --- /dev/null +++ b/doc/powervc-auth.md @@ -0,0 +1,16 @@ +# PowerVC Remote Loggging + +Configure rsyslog on your PowerVC instance to forward authentication messages to a remote logging solution. We use *10.32.64.1* as our remote syslog server in this example. + +Create a file new file in the **/etc/rsyslog.d** folder (eg. *remote.conf*) with the following content: + +```text +# Log authentication messages to remote host +auth.info,authpriv.info @10.32.64.1 +``` + +Restart the rsyslog service + +```shell +systemctl restart rsyslog +``` diff --git a/doc/rsyslog-auth.md b/doc/rsyslog-auth.md index fc8399a..58a7f6f 100644 --- a/doc/rsyslog-auth.md +++ b/doc/rsyslog-auth.md @@ -6,11 +6,11 @@ Create a file new file in the **/etc/rsyslog.d** folder (eg. *90-auth.conf*) wit ```text # Log authentication messages to remote host -auth.info,authpriv.info @10.32.64.1 +auth.*,authpriv.* @10.32.64.1 ``` Restart the rsyslog service ```shell -systemctl restart rsyslogd +systemctl restart rsyslog ``` diff --git a/gradle.properties b/gradle.properties index 1b16f7f..bcd09f8 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,3 +1,3 @@ id = syslogd group = biz.nellemann.syslogd -version = 1.2.2 +version = 1.2.3 diff --git a/src/main/java/biz/nellemann/syslogd/SyslogPrinter.java b/src/main/java/biz/nellemann/syslogd/SyslogPrinter.java index 2f1ad34..a02157c 100644 --- a/src/main/java/biz/nellemann/syslogd/SyslogPrinter.java +++ b/src/main/java/biz/nellemann/syslogd/SyslogPrinter.java @@ -3,6 +3,7 @@ package biz.nellemann.syslogd; import biz.nellemann.syslogd.msg.Facility; import biz.nellemann.syslogd.msg.Severity; import biz.nellemann.syslogd.msg.SyslogMessage; +import biz.nellemann.syslogd.parser.JsonUtil; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -89,7 +90,7 @@ public class SyslogPrinter { public static String toGelf(SyslogMessage msg) { StringBuilder sb = new StringBuilder("{ \"version\": \"1.1\","); sb.append(String.format("\"host\": \"%s\",", msg.hostname)); - sb.append(String.format("\"short_message\": \"%s\",", msg.message)); + sb.append(String.format("\"short_message\": \"%s\",", JsonUtil.encode(msg.message))); //sb.append(String.format("\"full_message\": \"%s\",", msg.message)); sb.append(String.format("\"timestamp\": %d,", msg.timestamp.getEpochSecond())); sb.append(String.format("\"level\": %d,", msg.severity.toNumber())); @@ -119,6 +120,7 @@ public class SyslogPrinter { sb.append("}, \"values\": [ "); sb.append(String.format("[ \"%d\", \"%s\" ]", msg.timestamp.getEpochSecond() * 1000000000l, getMessageLine(msg))); sb.append(" ] } ] }"); + log.debug(sb.toString()); return sb.toString(); } @@ -128,7 +130,7 @@ public class SyslogPrinter { sb.append(String.format("[%s.%s] ", msg.facility, msg.severity)); sb.append(String.format("%s ", msg.hostname)); sb.append(String.format("%s ", msg.application)); - sb.append(msg.message); + sb.append(JsonUtil.encode(msg.message)); return sb.toString(); } diff --git a/src/main/java/biz/nellemann/syslogd/parser/JsonUtil.java b/src/main/java/biz/nellemann/syslogd/parser/JsonUtil.java new file mode 100644 index 0000000..9a8918f --- /dev/null +++ b/src/main/java/biz/nellemann/syslogd/parser/JsonUtil.java @@ -0,0 +1,97 @@ +package biz.nellemann.syslogd.parser; + +/* + Code from https://gist.github.com/jjfiv/2ac5c081e088779f49aa, which is BSD licensed: http://lemurproject.org/galago-license +*/ + +public class JsonUtil { + + public static String encode(String input) { + + StringBuilder output = new StringBuilder(); + + for(int i=0; i 127) { + output.append(String.format("\\u%04x", chx)); + } else { + output.append(ch); + } + } + + return output.toString(); + } + + + public static String decode(String input) { + + StringBuilder builder = new StringBuilder(); + + int i = 0; + while (i < input.length()) { + char delimiter = input.charAt(i); i++; // consume letter or backslash + + if(delimiter == '\\' && i < input.length()) { + + // consume first after backslash + char ch = input.charAt(i); i++; + + if(ch == '\\' || ch == '/' || ch == '"' || ch == '\'') { + builder.append(ch); + } + else if(ch == 'n') builder.append('\n'); + else if(ch == 'r') builder.append('\r'); + else if(ch == 't') builder.append('\t'); + else if(ch == 'b') builder.append('\b'); + else if(ch == 'f') builder.append('\f'); + else if(ch == 'u') { + + StringBuilder hex = new StringBuilder(); + + // expect 4 digits + if (i+4 > input.length()) { + throw new RuntimeException("Not enough unicode digits! "); + } + for (char x : input.substring(i, i + 4).toCharArray()) { + if(!Character.isLetterOrDigit(x)) { + throw new RuntimeException("Bad character in unicode escape."); + } + hex.append(Character.toLowerCase(x)); + } + i+=4; // consume those four digits. + + int code = Integer.parseInt(hex.toString(), 16); + builder.append((char) code); + } else { + throw new RuntimeException("Illegal escape sequence: \\"+ch); + } + } else { // it's not a backslash, or it's the last character. + builder.append(delimiter); + } + } + + return builder.toString(); + } + +} diff --git a/src/test/groovy/biz/nellemann/syslogd/JsonUtilTest.groovy b/src/test/groovy/biz/nellemann/syslogd/JsonUtilTest.groovy new file mode 100644 index 0000000..7a05dd8 --- /dev/null +++ b/src/test/groovy/biz/nellemann/syslogd/JsonUtilTest.groovy @@ -0,0 +1,42 @@ +package biz.nellemann.syslogd + +import biz.nellemann.syslogd.parser.JsonUtil +import spock.lang.Specification + +class JsonUtilTest extends Specification { + + def "test short decode"() { + setup: + def testShort = 'Eating a piece of \u03c0 (pi)' + + when: + def result = JsonUtil.decode(testShort) + + then: + result == 'Eating a piece of π (pi)' + } + + def "test long decode"() { + setup: + def testLong = 'I stole this guy from wikipedia: \ud83d\ude02' // emoji "face with tears of joy" + + when: + def result = JsonUtil.decode(testLong) + + then: + result == 'I stole this guy from wikipedia: 😂' + } + + + def "test quotes decode"() { + setup: + def testQuote = 'here it comes \" to wreck the day...' + + when: + def result = JsonUtil.decode(testQuote) + + then: + result == 'here it comes " to wreck the day...' + } + +} diff --git a/src/test/groovy/biz/nellemann/syslogd/SyslogPrinterTest.groovy b/src/test/groovy/biz/nellemann/syslogd/SyslogPrinterTest.groovy index 00c17c4..b8fe4b7 100644 --- a/src/test/groovy/biz/nellemann/syslogd/SyslogPrinterTest.groovy +++ b/src/test/groovy/biz/nellemann/syslogd/SyslogPrinterTest.groovy @@ -7,7 +7,6 @@ import spock.lang.Specification class SyslogPrinterTest extends Specification { - void setup() { }