1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.logging.log4j.core.appender.nosql;
18
19 import java.io.Serializable;
20
21 import javax.jms.JMSException;
22
23 import org.apache.logging.log4j.Marker;
24 import org.apache.logging.log4j.ThreadContext;
25 import org.apache.logging.log4j.core.LogEvent;
26 import org.apache.logging.log4j.core.appender.AppenderLoggingException;
27 import org.apache.logging.log4j.core.appender.ManagerFactory;
28 import org.apache.logging.log4j.core.appender.db.AbstractDatabaseManager;
29 import org.apache.logging.log4j.core.util.Closer;
30 import org.apache.logging.log4j.message.MapMessage;
31 import org.apache.logging.log4j.util.BiConsumer;
32 import org.apache.logging.log4j.util.ReadOnlyStringMap;
33
34
35
36
37
38
39 public final class NoSqlDatabaseManager<W> extends AbstractDatabaseManager {
40 private static final NoSQLDatabaseManagerFactory FACTORY = new NoSQLDatabaseManagerFactory();
41
42 private final NoSqlProvider<NoSqlConnection<W, ? extends NoSqlObject<W>>> provider;
43
44 private NoSqlConnection<W, ? extends NoSqlObject<W>> connection;
45
46 private NoSqlDatabaseManager(final String name, final int bufferSize,
47 final NoSqlProvider<NoSqlConnection<W, ? extends NoSqlObject<W>>> provider) {
48 super(name, bufferSize);
49 this.provider = provider;
50 }
51
52 @Override
53 protected void startupInternal() {
54
55 }
56
57 @Override
58 protected boolean shutdownInternal() {
59
60 return Closer.closeSilently(this.connection);
61 }
62
63 @Override
64 protected void connectAndStart() {
65 try {
66 this.connection = this.provider.getConnection();
67 } catch (final Exception e) {
68 throw new AppenderLoggingException("Failed to get connection from NoSQL connection provider.", e);
69 }
70 }
71
72 @Deprecated
73 @Override
74 protected void writeInternal(final LogEvent event) {
75 writeInternal(event, null);
76 }
77
78 @Override
79 protected void writeInternal(final LogEvent event, final Serializable serializable) {
80 if (!this.isRunning() || this.connection == null || this.connection.isClosed()) {
81 throw new AppenderLoggingException(
82 "Cannot write logging event; NoSQL manager not connected to the database.");
83 }
84
85 final NoSqlObject<W> entity = this.connection.createObject();
86 if (serializable instanceof MapMessage) {
87 setFields((MapMessage<?, ?>) serializable, entity);
88 } else {
89 setFields(event, entity);
90 }
91
92 this.connection.insertObject(entity);
93 }
94
95 private void setFields(final MapMessage<?, ?> mapMessage, final NoSqlObject<W> noSqlObject) {
96
97 mapMessage.forEach(new BiConsumer<String, Object>() {
98 @Override
99 public void accept(final String key, final Object value) {
100 noSqlObject.set(key, value);
101 }
102 });
103 }
104
105 private void setFields(final LogEvent event, final NoSqlObject<W> entity) {
106 entity.set("level", event.getLevel());
107 entity.set("loggerName", event.getLoggerName());
108 entity.set("message", event.getMessage() == null ? null : event.getMessage().getFormattedMessage());
109
110 final StackTraceElement source = event.getSource();
111 if (source == null) {
112 entity.set("source", (Object) null);
113 } else {
114 entity.set("source", this.convertStackTraceElement(source));
115 }
116
117 final Marker marker = event.getMarker();
118 if (marker == null) {
119 entity.set("marker", (Object) null);
120 } else {
121 entity.set("marker", buildMarkerEntity(marker));
122 }
123
124 entity.set("threadId", event.getThreadId());
125 entity.set("threadName", event.getThreadName());
126 entity.set("threadPriority", event.getThreadPriority());
127 entity.set("millis", event.getTimeMillis());
128 entity.set("date", new java.util.Date(event.getTimeMillis()));
129
130 @SuppressWarnings("ThrowableResultOfMethodCallIgnored")
131 Throwable thrown = event.getThrown();
132 if (thrown == null) {
133 entity.set("thrown", (Object) null);
134 } else {
135 final NoSqlObject<W> originalExceptionEntity = this.connection.createObject();
136 NoSqlObject<W> exceptionEntity = originalExceptionEntity;
137 exceptionEntity.set("type", thrown.getClass().getName());
138 exceptionEntity.set("message", thrown.getMessage());
139 exceptionEntity.set("stackTrace", this.convertStackTrace(thrown.getStackTrace()));
140 while (thrown.getCause() != null) {
141 thrown = thrown.getCause();
142 final NoSqlObject<W> causingExceptionEntity = this.connection.createObject();
143 causingExceptionEntity.set("type", thrown.getClass().getName());
144 causingExceptionEntity.set("message", thrown.getMessage());
145 causingExceptionEntity.set("stackTrace", this.convertStackTrace(thrown.getStackTrace()));
146 exceptionEntity.set("cause", causingExceptionEntity);
147 exceptionEntity = causingExceptionEntity;
148 }
149
150 entity.set("thrown", originalExceptionEntity);
151 }
152
153 final ReadOnlyStringMap contextMap = event.getContextData();
154 if (contextMap == null) {
155 entity.set("contextMap", (Object) null);
156 } else {
157 final NoSqlObject<W> contextMapEntity = this.connection.createObject();
158 contextMap.forEach(new BiConsumer<String, String>() {
159 @Override
160 public void accept(final String key, final String val) {
161 contextMapEntity.set(key, val);
162 }
163 });
164 entity.set("contextMap", contextMapEntity);
165 }
166
167 final ThreadContext.ContextStack contextStack = event.getContextStack();
168 if (contextStack == null) {
169 entity.set("contextStack", (Object) null);
170 } else {
171 entity.set("contextStack", contextStack.asList().toArray());
172 }
173 }
174
175 private NoSqlObject<W> buildMarkerEntity(final Marker marker) {
176 final NoSqlObject<W> entity = this.connection.createObject();
177 entity.set("name", marker.getName());
178
179 final Marker[] parents = marker.getParents();
180 if (parents != null) {
181 @SuppressWarnings("unchecked")
182 final NoSqlObject<W>[] parentEntities = new NoSqlObject[parents.length];
183 for (int i = 0; i < parents.length; i++) {
184 parentEntities[i] = buildMarkerEntity(parents[i]);
185 }
186 entity.set("parents", parentEntities);
187 }
188 return entity;
189 }
190
191 @Override
192 protected boolean commitAndClose() {
193
194
195
196
197 return true;
198 }
199
200 private NoSqlObject<W>[] convertStackTrace(final StackTraceElement[] stackTrace) {
201 final NoSqlObject<W>[] stackTraceEntities = this.connection.createList(stackTrace.length);
202 for (int i = 0; i < stackTrace.length; i++) {
203 stackTraceEntities[i] = this.convertStackTraceElement(stackTrace[i]);
204 }
205 return stackTraceEntities;
206 }
207
208 private NoSqlObject<W> convertStackTraceElement(final StackTraceElement element) {
209 final NoSqlObject<W> elementEntity = this.connection.createObject();
210 elementEntity.set("className", element.getClassName());
211 elementEntity.set("methodName", element.getMethodName());
212 elementEntity.set("fileName", element.getFileName());
213 elementEntity.set("lineNumber", element.getLineNumber());
214 return elementEntity;
215 }
216
217
218
219
220
221
222
223
224
225 public static NoSqlDatabaseManager<?> getNoSqlDatabaseManager(final String name, final int bufferSize,
226 final NoSqlProvider<?> provider) {
227 return AbstractDatabaseManager.getManager(name, new FactoryData(bufferSize, provider), FACTORY);
228 }
229
230
231
232
233 private static final class FactoryData extends AbstractDatabaseManager.AbstractFactoryData {
234 private final NoSqlProvider<?> provider;
235
236 protected FactoryData(final int bufferSize, final NoSqlProvider<?> provider) {
237 super(bufferSize, null);
238 this.provider = provider;
239 }
240 }
241
242
243
244
245 private static final class NoSQLDatabaseManagerFactory implements
246 ManagerFactory<NoSqlDatabaseManager<?>, FactoryData> {
247 @Override
248 @SuppressWarnings("unchecked")
249 public NoSqlDatabaseManager<?> createManager(final String name, final FactoryData data) {
250 return new NoSqlDatabaseManager(name, data.getBufferSize(), data.provider);
251 }
252 }
253 }