|
@@ -18,10 +18,11 @@ package org.codelibs.fess.helper;
|
|
import java.util.Date;
|
|
import java.util.Date;
|
|
import java.util.LinkedHashMap;
|
|
import java.util.LinkedHashMap;
|
|
import java.util.Locale;
|
|
import java.util.Locale;
|
|
-import java.util.Map;
|
|
|
|
import java.util.concurrent.TimeUnit;
|
|
import java.util.concurrent.TimeUnit;
|
|
|
|
+import java.util.concurrent.atomic.AtomicInteger;
|
|
|
|
|
|
import javax.annotation.PostConstruct;
|
|
import javax.annotation.PostConstruct;
|
|
|
|
+import javax.annotation.PreDestroy;
|
|
|
|
|
|
import org.apache.logging.log4j.LogManager;
|
|
import org.apache.logging.log4j.LogManager;
|
|
import org.apache.logging.log4j.Logger;
|
|
import org.apache.logging.log4j.Logger;
|
|
@@ -38,9 +39,11 @@ import com.google.common.cache.LoadingCache;
|
|
*
|
|
*
|
|
*/
|
|
*/
|
|
public class CrawlerStatsHelper {
|
|
public class CrawlerStatsHelper {
|
|
|
|
+ private static final Logger logger = LogManager.getLogger(CrawlerStatsHelper.class);
|
|
|
|
+
|
|
private static final String BEGIN_KEY = "begin";
|
|
private static final String BEGIN_KEY = "begin";
|
|
|
|
|
|
- protected Logger logger = null;
|
|
|
|
|
|
+ protected Logger statsLogger = null;
|
|
|
|
|
|
protected String loggerName = "fess.log.crawler.stats";
|
|
protected String loggerName = "fess.log.crawler.stats";
|
|
|
|
|
|
@@ -48,22 +51,35 @@ public class CrawlerStatsHelper {
|
|
|
|
|
|
protected long cacheExpireAfterWrite = 10 * 60 * 1000L;
|
|
protected long cacheExpireAfterWrite = 10 * 60 * 1000L;
|
|
|
|
|
|
- protected LoadingCache<String, Map<String, Long>> statsCache;
|
|
|
|
|
|
+ protected LoadingCache<String, StatsObject> statsCache;
|
|
|
|
|
|
@PostConstruct
|
|
@PostConstruct
|
|
public void init() {
|
|
public void init() {
|
|
- logger = LogManager.getLogger(loggerName);
|
|
|
|
|
|
+ statsLogger = LogManager.getLogger(loggerName);
|
|
statsCache = CacheBuilder.newBuilder().maximumSize(maxCacheSize).expireAfterWrite(cacheExpireAfterWrite, TimeUnit.MILLISECONDS)
|
|
statsCache = CacheBuilder.newBuilder().maximumSize(maxCacheSize).expireAfterWrite(cacheExpireAfterWrite, TimeUnit.MILLISECONDS)
|
|
- .build(new CacheLoader<String, Map<String, Long>>() {
|
|
|
|
|
|
+ .build(new CacheLoader<String, StatsObject>() {
|
|
@Override
|
|
@Override
|
|
- public Map<String, Long> load(String key) {
|
|
|
|
- Map<String, Long> map = new LinkedHashMap<>();
|
|
|
|
- map.put(BEGIN_KEY, System.currentTimeMillis());
|
|
|
|
- return map;
|
|
|
|
|
|
+ public StatsObject load(String key) {
|
|
|
|
+ return new StatsObject();
|
|
}
|
|
}
|
|
});
|
|
});
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ @PreDestroy
|
|
|
|
+ public void destroy() {
|
|
|
|
+ if (logger.isDebugEnabled()) {
|
|
|
|
+ logger.debug("cache stats: {}", statsCache.stats());
|
|
|
|
+ }
|
|
|
|
+ statsCache.asMap().entrySet().stream().forEach(e -> {
|
|
|
|
+ final StatsObject data = e.getValue();
|
|
|
|
+ final Long begin = data.remove(BEGIN_KEY);
|
|
|
|
+ if (begin != null) {
|
|
|
|
+ printStats(e.getKey(), data, begin.longValue(), false);
|
|
|
|
+ }
|
|
|
|
+ });
|
|
|
|
+ ;
|
|
|
|
+ }
|
|
|
|
+
|
|
public void begin(final Object keyObj) {
|
|
public void begin(final Object keyObj) {
|
|
getCacheKey(keyObj).ifPresent(key -> {
|
|
getCacheKey(keyObj).ifPresent(key -> {
|
|
try {
|
|
try {
|
|
@@ -84,7 +100,7 @@ public class CrawlerStatsHelper {
|
|
public void record(final Object keyObj, final String action) {
|
|
public void record(final Object keyObj, final String action) {
|
|
getCacheKey(keyObj).ifPresent(key -> {
|
|
getCacheKey(keyObj).ifPresent(key -> {
|
|
try {
|
|
try {
|
|
- Map<String, Long> data = statsCache.getIfPresent(key);
|
|
|
|
|
|
+ final StatsObject data = statsCache.getIfPresent(key);
|
|
if (data != null) {
|
|
if (data != null) {
|
|
data.put(escapeValue(action), System.currentTimeMillis());
|
|
data.put(escapeValue(action), System.currentTimeMillis());
|
|
}
|
|
}
|
|
@@ -100,16 +116,12 @@ public class CrawlerStatsHelper {
|
|
public void done(final Object keyObj) {
|
|
public void done(final Object keyObj) {
|
|
getCacheKey(keyObj).ifPresent(key -> {
|
|
getCacheKey(keyObj).ifPresent(key -> {
|
|
try {
|
|
try {
|
|
- final Map<String, Long> data = statsCache.getIfPresent(key);
|
|
|
|
- if (data != null) {
|
|
|
|
|
|
+ final StatsObject data = statsCache.getIfPresent(key);
|
|
|
|
+ if (data != null && data.decrement() <= 0) {
|
|
statsCache.invalidate(key);
|
|
statsCache.invalidate(key);
|
|
final Long begin = data.remove(BEGIN_KEY);
|
|
final Long begin = data.remove(BEGIN_KEY);
|
|
if (begin != null) {
|
|
if (begin != null) {
|
|
- final StringBuilder buf = createStringBuffer(keyObj, begin.longValue());
|
|
|
|
- buf.append('\t').append("done:").append(System.currentTimeMillis() - begin.longValue());
|
|
|
|
- data.entrySet().stream().map(e -> escapeValue(e.getKey()) + ":" + (e.getValue().longValue() - begin.longValue()))
|
|
|
|
- .map(s -> "\t" + s).forEach(s -> buf.append(s));
|
|
|
|
- log(buf);
|
|
|
|
|
|
+ printStats(keyObj, data, begin.longValue(), true);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
} catch (Exception e) {
|
|
} catch (Exception e) {
|
|
@@ -121,6 +133,48 @@ public class CrawlerStatsHelper {
|
|
});
|
|
});
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ public void discard(final Object keyObj) {
|
|
|
|
+ getCacheKey(keyObj).ifPresent(key -> {
|
|
|
|
+ try {
|
|
|
|
+ final StatsObject data = statsCache.getIfPresent(key);
|
|
|
|
+ if (data != null) {
|
|
|
|
+ statsCache.invalidate(key);
|
|
|
|
+ }
|
|
|
|
+ } catch (Exception e) {
|
|
|
|
+ final StringBuilder buf = createStringBuffer(keyObj, System.currentTimeMillis());
|
|
|
|
+ buf.append('\t').append("action:done");
|
|
|
|
+ buf.append('\t').append("error:").append(escapeValue(e.getLocalizedMessage()).replaceAll("\\s", " "));
|
|
|
|
+ log(buf);
|
|
|
|
+ }
|
|
|
|
+ });
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ protected void printStats(final Object keyObj, final StatsObject data, final long begin, final boolean done) {
|
|
|
|
+ final StringBuilder buf = createStringBuffer(keyObj, begin);
|
|
|
|
+ if (done) {
|
|
|
|
+ buf.append('\t').append("done:").append(System.currentTimeMillis() - begin);
|
|
|
|
+ }
|
|
|
|
+ data.entrySet().stream().map(e -> escapeValue(e.getKey()) + ":" + (e.getValue().longValue() - begin)).map(s -> "\t" + s)
|
|
|
|
+ .forEach(s -> buf.append(s));
|
|
|
|
+ log(buf);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ public void runOnThread(final Object keyObj) {
|
|
|
|
+ getCacheKey(keyObj).ifPresent(key -> {
|
|
|
|
+ try {
|
|
|
|
+ final StatsObject data = statsCache.getIfPresent(key);
|
|
|
|
+ if (data != null) {
|
|
|
|
+ data.increment();
|
|
|
|
+ }
|
|
|
|
+ } catch (Exception e) {
|
|
|
|
+ final StringBuilder buf = createStringBuffer(keyObj, System.currentTimeMillis());
|
|
|
|
+ buf.append('\t').append("action:record");
|
|
|
|
+ buf.append('\t').append("error:").append(escapeValue(e.getLocalizedMessage()).replaceAll("\\s", " "));
|
|
|
|
+ log(buf);
|
|
|
|
+ }
|
|
|
|
+ });
|
|
|
|
+ }
|
|
|
|
+
|
|
private StringBuilder createStringBuffer(final Object keyObj, final long time) {
|
|
private StringBuilder createStringBuffer(final Object keyObj, final long time) {
|
|
final StringBuilder buf = new StringBuilder(1000);
|
|
final StringBuilder buf = new StringBuilder(1000);
|
|
buf.append("url:").append(getUrl(keyObj));
|
|
buf.append("url:").append(getUrl(keyObj));
|
|
@@ -160,7 +214,7 @@ public class CrawlerStatsHelper {
|
|
}
|
|
}
|
|
|
|
|
|
protected void log(final StringBuilder buf) {
|
|
protected void log(final StringBuilder buf) {
|
|
- logger.info(buf.toString());
|
|
|
|
|
|
+ statsLogger.info(buf.toString());
|
|
}
|
|
}
|
|
|
|
|
|
public void setLoggerName(String loggerName) {
|
|
public void setLoggerName(String loggerName) {
|
|
@@ -201,6 +255,25 @@ public class CrawlerStatsHelper {
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ public static class StatsObject extends LinkedHashMap<String, Long> {
|
|
|
|
+ private static final long serialVersionUID = 1L;
|
|
|
|
+
|
|
|
|
+ protected final AtomicInteger count;
|
|
|
|
+
|
|
|
|
+ public StatsObject() {
|
|
|
|
+ put(BEGIN_KEY, System.currentTimeMillis());
|
|
|
|
+ count = new AtomicInteger(1);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ public int increment() {
|
|
|
|
+ return count.incrementAndGet();
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ public int decrement() {
|
|
|
|
+ return count.decrementAndGet();
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
public enum StatsAction {
|
|
public enum StatsAction {
|
|
ACCESSED, //
|
|
ACCESSED, //
|
|
ACCESS_EXCEPTION, //
|
|
ACCESS_EXCEPTION, //
|