├── .gitignore
├── src
└── main
│ └── java
│ └── com
│ └── twimba
│ └── fluentd4log4j
│ ├── ManagedRawSocketSender.java
│ └── FluentdAppender.java
├── README.md
└── pom.xml
/.gitignore:
--------------------------------------------------------------------------------
1 | .classpath
2 | .project
3 |
--------------------------------------------------------------------------------
/src/main/java/com/twimba/fluentd4log4j/ManagedRawSocketSender.java:
--------------------------------------------------------------------------------
1 | package com.twimba.fluentd4log4j;
2 |
3 | import org.fluentd.logger.sender.RawSocketSender;
4 | import org.fluentd.logger.sender.Reconnector;
5 |
6 | public class ManagedRawSocketSender extends RawSocketSender
7 | {
8 |
9 | private boolean closed = false;
10 |
11 | public ManagedRawSocketSender()
12 | {
13 | super();
14 | }
15 |
16 | public ManagedRawSocketSender(String host, int port, int timeout, int bufferCapacity, Reconnector reconnector)
17 | {
18 | super(host, port, timeout, bufferCapacity, reconnector);
19 | if (isClosed())
20 | {
21 | throw new RuntimeException("Unable to start the fluentd sender.");
22 | }
23 | }
24 |
25 | public ManagedRawSocketSender(String host, int port, int timeout, int bufferCapacity)
26 | {
27 | super(host, port, timeout, bufferCapacity);
28 | }
29 |
30 | public ManagedRawSocketSender(String host, int port)
31 | {
32 | super(host, port);
33 | }
34 |
35 | @Override
36 | public void close()
37 | {
38 | super.close();
39 | closed = true;
40 | }
41 |
42 | public boolean isClosed()
43 | {
44 | return closed;
45 | }
46 |
47 | public void setClosed(boolean closed)
48 | {
49 | this.closed = closed;
50 | }
51 |
52 | }
53 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # fluentd4log4j
2 |
3 | [](https://gitter.im/tuxetuxe/fluentd4log4j?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
4 | _A Log4J appender to push log events to a fluentd server._
5 |
6 | ## How to Use
7 |
8 | ### Maven dependency
9 | ```
10 |
11 | com.twimba
12 | fluentd4log4j
13 | 1.0
14 |
15 | ```
16 |
17 | ### Configuration
18 | | property | default value | Description |
19 | | ------------- |------------------| -------------|
20 | | mdcKeys | "" | The MDC keys (comma separated) that should be added to the log structure. |
21 | | tagPrefix | ""| The fluentd tag prefix to be used |
22 | | tag | "log" | The fluentd tag to be used in all the log messages sent there |
23 | | host | "localhost" | The fluentd server host to where to send the log messages. |
24 | | port | 24224 | The fluentd server port to where to send the log messages. |
25 | | timeout | 15000 (15s) | The timeout (in milliseconds) to connect to the fluentd server|
26 | | bufferCapacity | 1048576 (1Mb) | The socket buffer capacity to connect to the fluentd server |
27 | | useConstantDelayReconnector| false | Switch from the default Exponential Delay reconnector to a constant delay reconnector |
28 |
29 | ### Example
30 | **log4j.properties**
31 | ```
32 | log4j.rootLogger=info, fluentd
33 | log4j.appender.fluentd=com.twimba.fluentd4log4j.FluentdAppender.java
34 | log4j.appender.fluentd.mdcKeys=user,host,whatever
35 | log4j.appender.fluentd.host=fluentdhost
36 | ```
37 | **fluentd configuration**
38 | ```
39 |
40 | type forward
41 | port 24224
42 |
43 |
44 |
45 | type stdout
46 |
47 | ```
48 |
49 | ## License
50 | This is available in the Apache Licence 2.0
51 | http://www.tldrlegal.com/license/apache-license-2.0-(apache-2.0)
52 |
--------------------------------------------------------------------------------
/pom.xml:
--------------------------------------------------------------------------------
1 |
2 | 4.0.0
3 |
4 |
5 | org.sonatype.oss
6 | oss-parent
7 | 7
8 |
9 |
10 | com.twimba
11 | fluentd4log4j
12 | 1.0.1
13 | jar
14 |
15 | Fluentd Log4j Appender
16 | Integration between fluentd and log4j
17 |
18 |
19 | 1.2.17
20 | 0.2.11
21 |
22 |
23 |
24 |
25 | org.fluentd
26 | fluent-logger
27 | ${fluentd.version}
28 |
29 |
30 | log4j
31 | log4j
32 | ${log4j.version}
33 |
34 |
35 |
36 |
37 |
38 | The Apache Software License, Version 2.0
39 | http://www.apache.org/licenses/LICENSE-2.0.txt
40 | repo
41 |
42 |
43 |
44 | http://www.twimba.com/fluentd4log4j
45 |
46 |
47 | scm:git:git@github.com:tuxetuxe/fluentd4log4j.git
48 | scm:git:git@github.com:tuxetuxe/fluentd4log4j.git
49 | git@github.com:tuxetuxe/fluentd4log4j.git
50 |
51 |
52 |
53 |
54 | tuxetuxe
55 | Luis Santos
56 | luis.santos+fluentd4log4j@twimba.com
57 | https://github.com/tuxetuxe
58 |
59 |
60 |
61 |
62 | Twimba
63 |
64 |
65 |
--------------------------------------------------------------------------------
/src/main/java/com/twimba/fluentd4log4j/FluentdAppender.java:
--------------------------------------------------------------------------------
1 | package com.twimba.fluentd4log4j;
2 |
3 | import java.net.InetAddress;
4 | import java.net.UnknownHostException;
5 | import java.util.HashMap;
6 | import java.util.Map;
7 |
8 | import org.apache.log4j.AppenderSkeleton;
9 | import org.apache.log4j.helpers.LogLog;
10 | import org.apache.log4j.spi.LoggingEvent;
11 | import org.fluentd.logger.Config;
12 | import org.fluentd.logger.FluentLogger;
13 | import org.fluentd.logger.sender.ConstantDelayReconnector;
14 | import org.fluentd.logger.sender.ExponentialDelayReconnector;
15 | import org.fluentd.logger.sender.Reconnector;
16 |
17 | public class FluentdAppender extends AppenderSkeleton
18 | {
19 |
20 | private FluentLogger fluentLogger;
21 |
22 | /**
23 | * The MDC keys (comma separated) that should be added to the log structure.
24 | * Default: none
25 | */
26 | private String mdcKeys = "";
27 |
28 | /**
29 | * The fluentd tag prefix to be used
30 | * Default: "" (empty string)
31 | */
32 | private String tagPrefix = "";
33 |
34 | /**
35 | * The fluentd tag to be used in all the log messages sent there.
36 | * Default: "log"
37 | */
38 | private String tag = "log";
39 | /**
40 | * The fluentd server host to where to send the log messages.
41 | * Default: "localhost"
42 | */
43 | private String host = "localhost";
44 | /**
45 | * The fluentd server port to where to send the log messages.
46 | * Default: 24224
47 | */
48 | private int port = 24224;
49 | /**
50 | * The timeout (in milliseconds) to connect to the fluentd server
51 | * Default: 15000 (15s)
52 | */
53 | private int timeout = 15 * 1000; // 15s
54 | /**
55 | * The socket buffer capacity to connect to the fluentd server
56 | * Default: 1048576 (1Mb)
57 | */
58 | private int bufferCapacity = 1024 * 1024; // 1M
59 |
60 | /**
61 | * Switch from the default Exponential Delay reconnector to a constant delay reconnector
62 | * Default: false (use the Exponential Delay reconnector)
63 | */
64 | private boolean useConstantDelayReconnector = false;
65 |
66 | /**
67 | * Adds a value with the current hostname. This value key is "host"
68 | *
69 | * Default: false
70 | */
71 | private boolean addHostname = false;
72 |
73 | @Override
74 | public void activateOptions()
75 | {
76 | Reconnector reconnector = null;
77 |
78 | if (useConstantDelayReconnector)
79 | {
80 | reconnector = new ConstantDelayReconnector();
81 | }
82 | else
83 | {
84 | reconnector = new ExponentialDelayReconnector();
85 | }
86 |
87 | System.setProperty(Config.FLUENT_SENDER_CLASS, ManagedRawSocketSender.class.getName());
88 |
89 | try
90 | {
91 | fluentLogger = FluentLogger.getLogger(tagPrefix, host, port, timeout, bufferCapacity, reconnector);
92 | LogLog.warn("FluentdAppender connected to fluentd! (host=" + host + ", port=" + port + ",timeout=" + timeout + ",bufferCapacity="
93 | + bufferCapacity + ",tagPrefix=" + tagPrefix + ")");
94 | }
95 | catch (Exception e)
96 | {
97 | LogLog.warn("FluentdAppender NOT connected to fluentd! (host=" + host + ", port=" + port + ",timeout=" + timeout + ",bufferCapacity="
98 | + bufferCapacity + ",tagPrefix=" + tagPrefix + ")");
99 | fluentLogger = null;
100 | }
101 | }
102 |
103 | @Override
104 | public void close()
105 | {
106 | if (fluentLogger != null)
107 | {
108 | fluentLogger.flush();
109 | fluentLogger.close();
110 | }
111 | }
112 |
113 | @Override
114 | public boolean requiresLayout()
115 | {
116 | return false;
117 | }
118 |
119 | @Override
120 | protected void append(LoggingEvent event)
121 | {
122 | if (fluentLogger == null)
123 | {
124 | // Ups! Something very wrong is going on here! Bail out!
125 | LogLog.debug("FluentdAppender has no fluentLogger. Please check your configuration and/or logs for errors!");
126 | return;
127 | }
128 | Map data = new HashMap();
129 | data.put("message", event.getMessage());
130 | data.put("loggerClass", event.getFQNOfLoggerClass());
131 | data.put("level", event.getLevel().toString());
132 | data.put("locationInformation", event.getLocationInformation().fullInfo);
133 | data.put("logger", event.getLoggerName());
134 | data.put("threadName", event.getThreadName());
135 | if (event.getThrowableStrRep() != null)
136 | {
137 | data.put("throwableInformation", event.getThrowableStrRep());
138 | }
139 | if (event.getNDC() != null)
140 | {
141 | data.put("NDC", event.getNDC());
142 | }
143 | for (String mdcKey : mdcKeys.split(","))
144 | {
145 | Object value = event.getMDC(mdcKey);
146 | if (value != null)
147 | {
148 | data.put(mdcKey, value);
149 | }
150 | }
151 |
152 | if (addHostname)
153 | {
154 | try
155 | {
156 | data.put("hostname", InetAddress.getLocalHost().getHostName());
157 | }
158 | catch (UnknownHostException e)
159 | {
160 | LogLog
161 | .warn("FluentdAppender is unable to get the current hostname. Please check your configuration and/or disable the addition of the hostname!");
162 | }
163 | }
164 | fluentLogger.log(tag, data);
165 | }
166 |
167 | //
168 | // Getters and Setters
169 | //
170 |
171 | public FluentLogger getFluentLogger()
172 | {
173 | return fluentLogger;
174 | }
175 |
176 | public void setFluentLogger(FluentLogger fluentLogger)
177 | {
178 | this.fluentLogger = fluentLogger;
179 | }
180 |
181 | public String getMdcKeys()
182 | {
183 | return mdcKeys;
184 | }
185 |
186 | public void setMdcKeys(String mdcKeys)
187 | {
188 | this.mdcKeys = mdcKeys;
189 | }
190 |
191 | public String getTagPrefix()
192 | {
193 | return tagPrefix;
194 | }
195 |
196 | public void setTagPrefix(String tagPrefix)
197 | {
198 | this.tagPrefix = tagPrefix;
199 | }
200 |
201 | public String getTag()
202 | {
203 | return tag;
204 | }
205 |
206 | public void setTag(String tag)
207 | {
208 | this.tag = tag;
209 | }
210 |
211 | public String getHost()
212 | {
213 | return host;
214 | }
215 |
216 | public void setHost(String host)
217 | {
218 | this.host = host;
219 | }
220 |
221 | public int getPort()
222 | {
223 | return port;
224 | }
225 |
226 | public void setPort(int port)
227 | {
228 | this.port = port;
229 | }
230 |
231 | public int getTimeout()
232 | {
233 | return timeout;
234 | }
235 |
236 | public void setTimeout(int timeout)
237 | {
238 | this.timeout = timeout;
239 | }
240 |
241 | public int getBufferCapacity()
242 | {
243 | return bufferCapacity;
244 | }
245 |
246 | public void setBufferCapacity(int bufferCapacity)
247 | {
248 | this.bufferCapacity = bufferCapacity;
249 | }
250 |
251 | public boolean isUseConstantDelayReconnector()
252 | {
253 | return useConstantDelayReconnector;
254 | }
255 |
256 | public void setUseConstantDelayReconnector(boolean useConstantDelayReconnector)
257 | {
258 | this.useConstantDelayReconnector = useConstantDelayReconnector;
259 | }
260 |
261 | public boolean isAddHostname()
262 | {
263 | return addHostname;
264 | }
265 |
266 | public void setAddHostname(boolean addHostname)
267 | {
268 | this.addHostname = addHostname;
269 | }
270 |
271 | }
--------------------------------------------------------------------------------