Skip to content

Commit bf52ed9

Browse files
committed
Throttling logger
1 parent 0f1b7ee commit bf52ed9

3 files changed

Lines changed: 101 additions & 2 deletions

File tree

api/src/org/labkey/api/util/logging/LogHelper.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import org.apache.logging.log4j.LogManager;
44
import org.apache.logging.log4j.Logger;
5+
import org.apache.logging.log4j.spi.ExtendedLogger;
56

67
import java.util.Map;
78
import java.util.concurrent.ConcurrentHashMap;
@@ -44,4 +45,9 @@ public static String getLabKeyLogDir()
4445
{
4546
return System.getProperty(LOG_HOME_PROPERTY_NAME);
4647
}
48+
49+
public static Logger getThrottlingLogger(Class<?> c, String note)
50+
{
51+
return new ThrottlingLogger((ExtendedLogger)getLogger(c, note));
52+
}
4753
}
Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
package org.labkey.api.util.logging;
2+
3+
import org.apache.logging.log4j.Level;
4+
import org.apache.logging.log4j.Marker;
5+
import org.apache.logging.log4j.message.Message;
6+
import org.apache.logging.log4j.message.MessageFactory;
7+
import org.apache.logging.log4j.spi.ExtendedLogger;
8+
import org.apache.logging.log4j.spi.ExtendedLoggerWrapper;
9+
import org.labkey.api.cache.Cache;
10+
import org.labkey.api.cache.CacheManager;
11+
12+
import java.util.concurrent.atomic.AtomicInteger;
13+
14+
public class ThrottlingLogger extends ExtendedLoggerWrapper
15+
{
16+
private static final Cache<String, AtomicInteger> THROTTLING_CACHE = CacheManager.getBlockingCache(500, CacheManager.HOUR, "Throttle for Loggers", (_, _) -> new AtomicInteger(0));
17+
private static final Message DUMMY_MESSAGE = new Message()
18+
{
19+
@Override
20+
public String getFormattedMessage()
21+
{
22+
return null;
23+
}
24+
25+
@Override
26+
public Object[] getParameters()
27+
{
28+
return null;
29+
}
30+
31+
@Override
32+
public Throwable getThrowable()
33+
{
34+
return null;
35+
}
36+
};
37+
38+
public ThrottlingLogger(ExtendedLogger logger)
39+
{
40+
super(logger, logger.getName(), new ThrottlingMessageFactory(logger.getMessageFactory(), 20));
41+
}
42+
43+
@Override
44+
public void logMessage(final String fqcn, final Level level, final Marker marker, final Message message, final Throwable t)
45+
{
46+
if (message != DUMMY_MESSAGE)
47+
super.logMessage(fqcn, level, marker, message, t);
48+
}
49+
50+
private static class ThrottlingMessageFactory implements MessageFactory
51+
{
52+
private final MessageFactory _factory;
53+
private final int _maxBurst;
54+
55+
private ThrottlingMessageFactory(MessageFactory factory, int maxBurst)
56+
{
57+
_factory = factory;
58+
_maxBurst = maxBurst;
59+
}
60+
61+
@Override
62+
public Message newMessage(Object message)
63+
{
64+
String key = message == null ? "null" : message.toString();
65+
return shouldLog(key) ? _factory.newMessage(message) : DUMMY_MESSAGE;
66+
}
67+
68+
@Override
69+
public Message newMessage(String message)
70+
{
71+
return shouldLog(message) ? _factory.newMessage(message) : DUMMY_MESSAGE;
72+
}
73+
74+
@Override
75+
public Message newMessage(String message, Object... params)
76+
{
77+
return shouldLog(message) ? _factory.newMessage(message, params) : DUMMY_MESSAGE;
78+
}
79+
80+
private boolean shouldLog(String message)
81+
{
82+
AtomicInteger count = THROTTLING_CACHE.get(message);
83+
84+
if (count.intValue() < _maxBurst)
85+
{
86+
count.incrementAndGet();
87+
return true;
88+
}
89+
90+
return false;
91+
}
92+
}
93+
}

search/src/org/labkey/search/model/LuceneSearchServiceImpl.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -161,7 +161,7 @@
161161

162162
public class LuceneSearchServiceImpl extends AbstractSearchService implements SearchMXBean
163163
{
164-
private static final Logger _log = LogHelper.getLogger(LuceneSearchServiceImpl.class, "Full-text searching indexing operations");
164+
private static final Logger _log = LogHelper.getThrottlingLogger(LuceneSearchServiceImpl.class, "Full-text searching indexing operations");
165165

166166
// Changes to _index are rare (only when admin changes the index path), but we want any changes to be visible to
167167
// other threads immediately. Initialize to Noop class to prevent rare NPE (e.g., system maintenance runs before index
@@ -1334,7 +1334,7 @@ private void logAsWarning(WebdavResource r, String message)
13341334

13351335
private void logAsWarning(WebdavResource r, String message, @Nullable String rootMessage)
13361336
{
1337-
_log.warn("Can't index file \"" + getNameToLog(r) + "\" due to: " + message + (null != rootMessage ? " [" + rootMessage + "]" : ""));
1337+
_log.warn("Can't index file \"{}\" due to: {}{}", getNameToLog(r), message, null != rootMessage ? " [" + rootMessage + "]" : "");
13381338
}
13391339

13401340
private static class PreProcessingException extends Exception

0 commit comments

Comments
 (0)