From a29824e067e2dd09e05a07862020daeb4f51089c Mon Sep 17 00:00:00 2001 From: Steve Hu Date: Mon, 7 Feb 2022 18:35:27 -0500 Subject: [PATCH] =?UTF-8?q?fixes=20#1102=20update=20the=20LoggerGetLogCont?= =?UTF-8?q?entHandler=20to=20return=20map=20and=20h=E2=80=A6=20(#1103)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fixes #1102 update the LoggerGetLogContentHandler to return map and handle parsing exception * change the return to map of maps and filter record by level and loggerName --- .../handler/LoggerGetLogContentsHandler.java | 83 ++++++++++++------- 1 file changed, 53 insertions(+), 30 deletions(-) diff --git a/logger-config/src/main/java/com/networknt/logging/handler/LoggerGetLogContentsHandler.java b/logger-config/src/main/java/com/networknt/logging/handler/LoggerGetLogContentsHandler.java index ab24a94502..86c2816fc9 100644 --- a/logger-config/src/main/java/com/networknt/logging/handler/LoggerGetLogContentsHandler.java +++ b/logger-config/src/main/java/com/networknt/logging/handler/LoggerGetLogContentsHandler.java @@ -12,6 +12,7 @@ import com.networknt.logging.model.LoggerConfig; import io.undertow.server.HttpServerExchange; import io.undertow.util.Headers; +import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.BufferedReader; @@ -26,12 +27,18 @@ * */ public class LoggerGetLogContentsHandler implements LightHttpHandler { - + private static final Logger logger = LoggerFactory.getLogger(LoggerGetLogContentsHandler.class); public static final String CONFIG_NAME = "logging"; private static final String TIMESTAMP_FORMAT = "yyyy-MM-dd'T'HH:mm:ss.SSSZZZZ"; static final String STATUS_LOGGER_INFO_DISABLED = "ERR12108"; static final String STATUS_LOGGER_FILE_INVALID = "ERR12110"; static final String TIMESTAMP_LOG_KEY = "timestamp"; + static final String LEVEL_LOG_KEY = "level"; + static final String LOGGER_LOG_KEY = "logger"; + static final String ROOT_LOGGER_NAME = "ROOT"; + public static final int DEFAULT_LIMIT = 100; + public static final int DEFAULT_OFFSET = 0; + private static final ObjectMapper mapper = Config.getInstance().getMapper(); @Override @@ -39,19 +46,24 @@ public void handleRequest(HttpServerExchange exchange) throws IOException, Parse LoggerConfig config = (LoggerConfig) Config.getInstance().getJsonObjectConfig(CONFIG_NAME, LoggerConfig.class); long requestTimeRangeStart = System.currentTimeMillis()- config.getLogStart(); long requestTimeRangeEnd = System.currentTimeMillis(); + int limit = DEFAULT_LIMIT; + int offset = DEFAULT_OFFSET; Map> parameters = exchange.getQueryParameters(); String loggerName = parameters.containsKey("loggerName")? parameters.get("loggerName").getFirst() : null; Level loggerLevel = parameters.containsKey("loggerLevel")? Level.toLevel(parameters.get("loggerLevel").getFirst(), Level.ERROR): Level.ERROR; if (config.isEnabled()) { - + if(parameters.containsKey("limit")) + limit = Integer.parseInt(parameters.get("limit").getFirst()); + if(parameters.containsKey("offset")) + offset = Integer.parseInt(parameters.get("offset").getFirst()); if(parameters.containsKey("startTime")) requestTimeRangeStart = Long.parseLong(parameters.get("startTime").getFirst()); if(parameters.containsKey("endTime")) requestTimeRangeEnd = Long.parseLong(parameters.get("endTime").getFirst()); - - this.getLogEntries(requestTimeRangeStart, requestTimeRangeEnd, exchange, loggerName, loggerLevel); + if(logger.isDebugEnabled()) logger.debug("startTime = " + requestTimeRangeStart + " endTime = " + requestTimeRangeEnd + " loggerName = " + loggerName + " loggerLevel = " + loggerLevel + " offset = " + offset + " limit = " + limit); + this.getLogEntries(requestTimeRangeStart, requestTimeRangeEnd, exchange, loggerName, loggerLevel, offset, limit); } else { logger.error("Logging is disabled in logging.yml"); setExchangeStatus(exchange, STATUS_LOGGER_INFO_DISABLED); @@ -67,17 +79,17 @@ public void handleRequest(HttpServerExchange exchange) throws IOException, Parse * @param endTime - the request end time range when grabbing log entries * @param exchange - HttpServer exchange */ - private void getLogEntries(long startTime, long endTime, HttpServerExchange exchange, String loggerName, Level loggerLevel) throws IOException, ParseException { - List logContent = new ArrayList<>(); + private void getLogEntries(long startTime, long endTime, HttpServerExchange exchange, String loggerName, Level loggerLevel, int offset, int limit) throws IOException, ParseException { + // the return is a map of list with key is the loggerName. There might be multiple of loggers in the logback.xml file. + Map> logContent = new HashMap<>(); LoggerContext lc = (LoggerContext) LoggerFactory.getILoggerFactory(); for (ch.qos.logback.classic.Logger log : lc.getLoggerList()) { - /* only parse the context if the log is valid */ - if (log.getLevel() != null && log.getLevel().isGreaterOrEqual(loggerLevel) && (loggerName==null || log.getName().equalsIgnoreCase(loggerName))) { - List> logs = this.parseLogContents(startTime, endTime, log); - if(!logs.isEmpty()) - logContent.addAll(logs); + if (loggerName == null || log.getName().equalsIgnoreCase(loggerName)) { + Map logMap = this.parseLogContents(startTime, endTime, log, loggerLevel, offset, limit); + if(logMap.size() > 0 && (Integer)logMap.get("total") > 0) + logContent.put(log.getName(), logMap); } } exchange.getResponseHeaders().put(Headers.CONTENT_TYPE, ContentType.APPLICATION_JSON.value()); @@ -91,16 +103,14 @@ private void getLogEntries(long startTime, long endTime, HttpServerExchange exch * @param log - the log context * @return - returns the string response for log entry request. */ - private List> parseLogContents(long startTime, long endTime, ch.qos.logback.classic.Logger log) throws IOException, ParseException { - List> res = new ArrayList<>(); + private Map parseLogContents(long startTime, long endTime, ch.qos.logback.classic.Logger log, Level loggerLevel, int offset, int limit) throws IOException, ParseException { + Map res = new HashMap<>(); for(Iterator> it = log.iteratorForAppenders(); it.hasNext();) { Appender logEvent = it.next(); if(logEvent.getClass().equals(RollingFileAppender.class)) { FileReader reader = new FileReader(((RollingFileAppender) logEvent).getFile()); BufferedReader bufferedReader = new BufferedReader(reader); - List> parsedLogLines = this.parseAppenderFile(bufferedReader, startTime, endTime); - if(!parsedLogLines.isEmpty()) - res.addAll(parsedLogLines); + res = this.parseAppenderFile(bufferedReader, startTime, endTime, log, loggerLevel, offset, limit); } } return res; @@ -116,23 +126,36 @@ private List> parseLogContents(long startTime, long endTime, * @throws ParseException - exception when parsing the file * @throws IOException - exception when trying to load the file */ - private List> parseAppenderFile(BufferedReader bufferedReader, long startTime, long endTime) throws ParseException, IOException { - List> res = new ArrayList<>(); + private Map parseAppenderFile(BufferedReader bufferedReader, long startTime, long endTime, ch.qos.logback.classic.Logger log, Level loggerLevel, int offset, int limit) throws ParseException, IOException { + Map logMap = new HashMap<>(); + List> logs = new ArrayList<>(); + int index = 0; String currentLine; - while((currentLine=bufferedReader.readLine()) != null) { - - @SuppressWarnings("unchecked") - Map logLine = mapper.readValue(currentLine, Map.class); - - /* Grab the log entry as a map, and check to see if the timestamp falls within range of startTime and endTime */ - if(logLine != null && logLine.containsKey(TIMESTAMP_LOG_KEY)) { - SimpleDateFormat timestampFormat = new SimpleDateFormat(TIMESTAMP_FORMAT); - long logTime = timestampFormat.parse(logLine.get(TIMESTAMP_LOG_KEY).toString()).toInstant().toEpochMilli(); - if(logTime > startTime && logTime < endTime) { - res.add(logLine); + try { + while ((currentLine = bufferedReader.readLine()) != null) { + @SuppressWarnings("unchecked") + Map logLine = mapper.readValue(currentLine, Map.class); + /* Grab the log entry as a map, and check to see if the timestamp falls within range of startTime and endTime */ + if (logLine != null && logLine.containsKey(TIMESTAMP_LOG_KEY) && logLine.containsKey(LEVEL_LOG_KEY) && logLine.containsKey(LOGGER_LOG_KEY)) { + SimpleDateFormat timestampFormat = new SimpleDateFormat(TIMESTAMP_FORMAT); + long logTime = timestampFormat.parse(logLine.get(TIMESTAMP_LOG_KEY).toString()).toInstant().toEpochMilli(); + String levelStr = (String)logLine.get(LEVEL_LOG_KEY); + Level logLevel = Level.valueOf(levelStr.trim()); + String logLogger = (String)logLine.get(LOGGER_LOG_KEY); + if (logTime > startTime && logTime < endTime && logLevel.isGreaterOrEqual(loggerLevel) && (log.getName().equals(ROOT_LOGGER_NAME) || logLogger.startsWith(log.getName()))) { + if(index >= offset && logs.size() < limit) { + logs.add(logLine); + } + // the total number of entries between the startTime and endTime. + index++; + } } } + } catch (Exception e) { + // any exception here might be the format is not JSON for the logger. For example Audit logger etc. Ignore it. } - return res; + logMap.put("total", index); + logMap.put("logs", logs); + return logMap; } }