Skip to content

Commit ec2a056

Browse files
committed
SMX4-1256: Add Logstash event message format
git-svn-id: https://svn.apache.org/repos/asf/servicemix/smx4/features/trunk@1393356 13f79535-47bb-0310-9956-ffa450edef68
1 parent 1c9f627 commit ec2a056

File tree

11 files changed

+431
-62
lines changed

11 files changed

+431
-62
lines changed

.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -2,5 +2,6 @@
22
.classpath
33
.project
44
target
5+
.idea
56
*.i??
67
velocity.log

osgi-logging/jms-appender/pom.xml

+31-12
Original file line numberDiff line numberDiff line change
@@ -34,21 +34,42 @@
3434
<packaging>bundle</packaging>
3535

3636
<dependencies>
37-
<dependency>
37+
<dependency>
3838
<groupId>org.ops4j.pax.logging</groupId>
39-
<artifactId>pax-logging-api</artifactId>
39+
<artifactId>pax-logging-service</artifactId>
4040
<version>${pax.logging.version}</version>
4141
</dependency>
4242
<dependency>
4343
<groupId>org.ops4j.pax.logging</groupId>
44-
<artifactId>pax-logging-service</artifactId>
44+
<artifactId>pax-logging-api</artifactId>
4545
<version>${pax.logging.version}</version>
4646
</dependency>
4747
<dependency>
4848
<groupId>org.apache.activemq</groupId>
4949
<artifactId>activemq-core</artifactId>
5050
<version>${activemq.version}</version>
5151
</dependency>
52+
<dependency>
53+
<groupId>org.json</groupId>
54+
<artifactId>json</artifactId>
55+
<version>20090211</version>
56+
</dependency>
57+
58+
<dependency>
59+
<groupId>org.apache.camel</groupId>
60+
<artifactId>camel-test</artifactId>
61+
<scope>test</scope>
62+
</dependency>
63+
<dependency>
64+
<groupId>org.apache.activemq</groupId>
65+
<artifactId>activemq-camel</artifactId>
66+
<scope>test</scope>
67+
</dependency>
68+
<dependency>
69+
<groupId>org.slf4j</groupId>
70+
<artifactId>slf4j-log4j12</artifactId>
71+
<scope>test</scope>
72+
</dependency>
5273
</dependencies>
5374

5475
<build>
@@ -61,16 +82,14 @@
6182
<instructions>
6283
<Bundle-SymbolicName>${pom.artifactId}</Bundle-SymbolicName>
6384
<Import-Package>
64-
org.ops4j.pax.logging;resolution:=optional,
65-
org.osgi.service.blueprint;resolution:=optional,
66-
org.ops4j.pax.logging.spi*;resolution:=optional,
67-
org.slf4j,
68-
javax.jms,
69-
org.apache.activemq
85+
*
7086
</Import-Package>
71-
<Export-Package>
72-
org.apache.servicemix.logging
73-
</Export-Package>
87+
<Private-Package>
88+
org.apache.servicemix.logging.jms
89+
</Private-Package>
90+
<Embed-Dependency>
91+
json
92+
</Embed-Dependency>
7493
</instructions>
7594
</configuration>
7695
</plugin>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
/**
2+
* Licensed to the Apache Software Foundation (ASF) under one or more
3+
* contributor license agreements. See the NOTICE file distributed with
4+
* this work for additional information regarding copyright ownership.
5+
* The ASF licenses this file to You under the Apache License, Version 2.0
6+
* (the "License"); you may not use this file except in compliance with
7+
* 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, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
package org.apache.servicemix.logging.jms;
18+
19+
import org.ops4j.pax.logging.spi.PaxLoggingEvent;
20+
21+
import java.text.SimpleDateFormat;
22+
import java.util.Date;
23+
24+
/**
25+
* Default event logging format for the JMS appender
26+
*/
27+
public class DefaultLoggingEventFormat implements LoggingEventFormat {
28+
29+
private SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ");
30+
31+
public String toString(PaxLoggingEvent paxLoggingEvent) {
32+
StringBuilder writer = new StringBuilder();
33+
34+
writer.append("Error");
35+
writer.append(",\n \"timestamp\" : " + formatDate(paxLoggingEvent.getTimeStamp()));
36+
writer.append(",\n \"level\" : " + paxLoggingEvent.getLevel().toString());
37+
writer.append(",\n \"logger\" : " + paxLoggingEvent.getLoggerName());
38+
writer.append(",\n \"thread\" : " + paxLoggingEvent.getThreadName());
39+
writer.append(",\n \"message\" : " + paxLoggingEvent.getMessage());
40+
41+
String[] throwable = paxLoggingEvent.getThrowableStrRep();
42+
if (throwable != null) {
43+
writer.append(",\n \"exception\" : [");
44+
for (int i = 0; i < throwable.length; i++) {
45+
if (i != 0)
46+
writer.append(", " + throwable[i]);
47+
}
48+
writer.append("]");
49+
}
50+
51+
writer.append(",\n \"properties\" : { ");
52+
boolean first = true;
53+
for (Object key : paxLoggingEvent.getProperties().keySet()) {
54+
if (first) {
55+
first = false;
56+
} else {
57+
writer.append(", ");
58+
}
59+
writer.append("key : " + key.toString());
60+
writer.append(": " + paxLoggingEvent.getProperties().get(key).toString());
61+
}
62+
writer.append(" }");
63+
writer.append("\n}");
64+
return writer.toString();
65+
}
66+
67+
private String formatDate(long timestamp) {
68+
return simpleDateFormat.format(new Date(timestamp));
69+
}
70+
}

osgi-logging/jms-appender/src/main/java/org/apache/servicemix/logging/JMSAppender.java osgi-logging/jms-appender/src/main/java/org/apache/servicemix/logging/jms/JMSAppender.java

+17-49
Original file line numberDiff line numberDiff line change
@@ -14,35 +14,38 @@
1414
* See the License for the specific language governing permissions and
1515
* limitations under the License.
1616
*/
17-
package org.apache.servicemix.logging;
17+
package org.apache.servicemix.logging.jms;
1818

1919
import org.ops4j.pax.logging.spi.PaxAppender;
2020
import org.ops4j.pax.logging.spi.PaxLoggingEvent;
2121
import org.slf4j.Logger;
2222
import org.slf4j.LoggerFactory;
2323

2424
import javax.jms.*;
25-
import java.text.SimpleDateFormat;
26-
import java.util.Date;
2725

2826
public class JMSAppender implements PaxAppender {
2927

3028
private static final transient Logger LOG = LoggerFactory.getLogger(JMSAppender.class);
3129

30+
private static final String DEFAULT_EVENT_FORMAT = "default";
31+
private static final String LOGSTASH_EVENT_FORMAT = "logstash";
32+
33+
3234
private ConnectionFactory jmsConnectionFactory;
3335
private Connection connection;
3436
private Session session;
3537
private MessageProducer publisher;
3638
private Topic topic;
3739
private String destinationName;
3840

39-
private SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ");
41+
private LoggingEventFormat format = new DefaultLoggingEventFormat();
42+
43+
4044

4145
public void init() {
4246
/*
4347
* Create connection. Create session from connection; false means
4448
* session is not transacted.
45-
* Finally, close connection.
4649
*/
4750
try {
4851
connection = jmsConnectionFactory.createConnection();
@@ -70,56 +73,14 @@ public void close() {
7073
}
7174

7275
public void doAppend(PaxLoggingEvent paxLoggingEvent) {
73-
7476
try {
75-
StringBuilder writer = new StringBuilder();
76-
77-
writer.append("Error");
78-
writer.append(",\n \"timestamp\" : " + formatDate(paxLoggingEvent.getTimeStamp()));
79-
writer.append(",\n \"level\" : " + paxLoggingEvent.getLevel().toString());
80-
writer.append(",\n \"logger\" : " + paxLoggingEvent.getLoggerName());
81-
writer.append(",\n \"thread\" : " + paxLoggingEvent.getThreadName());
82-
writer.append(",\n \"message\" : " + paxLoggingEvent.getMessage());
83-
84-
String[] throwable = paxLoggingEvent.getThrowableStrRep();
85-
if (throwable != null) {
86-
writer.append(",\n \"exception\" : [");
87-
for (int i = 0; i < throwable.length; i++) {
88-
if (i != 0)
89-
writer.append(", " + throwable[i]);
90-
}
91-
writer.append("]");
92-
}
93-
94-
writer.append(",\n \"properties\" : { ");
95-
boolean first = true;
96-
for (Object key : paxLoggingEvent.getProperties().keySet()) {
97-
if (first) {
98-
first = false;
99-
} else {
100-
writer.append(", ");
101-
}
102-
writer.append("key : " + key.toString());
103-
writer.append(": " + paxLoggingEvent.getProperties().get(key).toString());
104-
}
105-
writer.append(" }");
106-
writer.append("\n}");
107-
10877
// Send message to the destination
10978
TextMessage message = session.createTextMessage();
110-
message.setText(writer.toString());
79+
message.setText(format.toString(paxLoggingEvent));
11180
publisher.send(message);
112-
113-
// System.out.println(">> Message created : " + writer.toString());
114-
115-
} catch (Exception e) {
81+
} catch (JMSException e) {
11682
e.printStackTrace();
11783
}
118-
119-
}
120-
121-
private String formatDate(long timestamp) {
122-
return simpleDateFormat.format(new Date(timestamp));
12384
}
12485

12586
public void setJmsConnectionFactory(ConnectionFactory jmsConnectionFactory) {
@@ -130,4 +91,11 @@ public void setDestinationName(String destinationName) {
13091
this.destinationName = destinationName;
13192
}
13293

94+
public void setFormat(String name) {
95+
if (LOGSTASH_EVENT_FORMAT.equals(name)) {
96+
format = new LogstashEventFormat();
97+
} else {
98+
format = new DefaultLoggingEventFormat();
99+
}
100+
}
133101
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
/**
2+
* Licensed to the Apache Software Foundation (ASF) under one or more
3+
* contributor license agreements. See the NOTICE file distributed with
4+
* this work for additional information regarding copyright ownership.
5+
* The ASF licenses this file to You under the Apache License, Version 2.0
6+
* (the "License"); you may not use this file except in compliance with
7+
* 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, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
package org.apache.servicemix.logging.jms;
18+
19+
import org.ops4j.pax.logging.spi.PaxLoggingEvent;
20+
21+
/**
22+
* Interface to represent an event message format, used for serializing log events into JMS messages
23+
*/
24+
public interface LoggingEventFormat {
25+
26+
public String toString(PaxLoggingEvent event);
27+
28+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
/**
2+
* Licensed to the Apache Software Foundation (ASF) under one or more
3+
* contributor license agreements. See the NOTICE file distributed with
4+
* this work for additional information regarding copyright ownership.
5+
* The ASF licenses this file to You under the Apache License, Version 2.0
6+
* (the "License"); you may not use this file except in compliance with
7+
* 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, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
package org.apache.servicemix.logging.jms;
18+
19+
import org.json.JSONArray;
20+
import org.json.JSONException;
21+
import org.json.JSONObject;
22+
import org.ops4j.pax.logging.spi.PaxLoggingEvent;
23+
24+
import java.text.DateFormat;
25+
import java.text.SimpleDateFormat;
26+
import java.util.Date;
27+
import java.util.Map;
28+
29+
/**
30+
* Creates a log message in Logstash' internal message format,
31+
* cfr. https://github.com/logstash/logstash/wiki/logstash's-internal-message-format
32+
*/
33+
public class LogstashEventFormat implements LoggingEventFormat {
34+
35+
protected static final DateFormat TIMESTAMP_FORMAT = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'");
36+
37+
protected static final String FIELDS = "@fields";
38+
protected static final String MESSAGE = "@message";
39+
protected static final String SOURCE = "@source";
40+
protected static final String TAGS = "@tags";
41+
protected static final String TIMESTAMP = "@timestamp";
42+
43+
public String toString(PaxLoggingEvent event) {
44+
JSONObject object = new JSONObject();
45+
try {
46+
object.put(MESSAGE, event.getMessage());
47+
object.put(SOURCE, event.getLoggerName());
48+
object.put(TIMESTAMP, TIMESTAMP_FORMAT.format(new Date(event.getTimeStamp())));
49+
50+
JSONObject fields = new JSONObject();
51+
for (Object property : event.getProperties().entrySet()) {
52+
Map.Entry<String, Object> entry = (Map.Entry<String, Object>) property;
53+
fields.put(entry.getKey(), entry.getValue().toString());
54+
}
55+
56+
object.put(FIELDS, fields);
57+
58+
JSONArray tags = new JSONArray();
59+
tags.put(event.getLevel().toString());
60+
object.put(TAGS, tags);
61+
} catch (JSONException e) {
62+
// let's return a minimal, String-based message representation instead
63+
return "{ \"" + MESSAGE + "\" : " + event.getMessage() + "}";
64+
}
65+
return object.toString();
66+
}
67+
68+
}

osgi-logging/jms-appender/src/main/resources/OSGI-INF/blueprint/config.xml

+2-1
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,10 @@
2525
<!-- Need OSGI JMS Connection Factory Service exposed -->
2626
<reference id="jmsConnectionFactory" interface="javax.jms.ConnectionFactory"/>
2727

28-
<bean id="appender" class="org.apache.servicemix.logging.JMSAppender" init-method="init" destroy-method="close">
28+
<bean id="appender" class="org.apache.servicemix.logging.jms.JMSAppender" init-method="init" destroy-method="close">
2929
<property name="jmsConnectionFactory" ref="jmsConnectionFactory"/>
3030
<property name="destinationName" value="${destinationName}" />
31+
<property name="format" value="${format}"/>
3132
</bean>
3233

3334
<service ref="appender" interface="org.ops4j.pax.logging.spi.PaxAppender">

0 commit comments

Comments
 (0)