`

Log4J日志解析

    博客分类:
  • Java
阅读更多

在有些场景下,需要解析Log4J的日志,以为己用。比如,根据关键字查询日志,用以定位问题等。就查询日志这个问题而论,通常的做法是登陆线上机器,grep一把日志目录,得到相关信息。这种做法有两个不好或者说不便捷的问题:首先要登陆线上机器,二来就是若有多台服务器,必须人肉的挨个儿查找,比较费时费力。

下面给出的解决方法是,分析log4j的配置文件,得到所有的Appender,然后再根据Appender中的日志路径、ConversionPattern等信息,去解析相应的日志文件,继而得到我们想要的信息,如Level,Logger、Message等信息。

闲话上说,直接上代码啦。

 

public final class ConversionRule {

	private boolean followedByQuotedString;
	private int beginIndex;
	private int length;
	private int minWidth = -1;
	private int maxWidth = -1;
	private String placeholderName;
	private String modifier;
	private Map<String, Object> properties = new HashMap<String, Object>();

	public boolean isFollowedByQuotedString() {
		return followedByQuotedString;
	}

	public void setFollowedByQuotedString(boolean followedByQuotedString) {
		this.followedByQuotedString = followedByQuotedString;
	}

	public int getBeginIndex() {
		return beginIndex;
	}

	public void setBeginIndex(int beginIndex) {
		this.beginIndex = beginIndex;
	}

	public int getLength() {
		return length;
	}

	public void setLength(int length) {
		this.length = length;
	}

	public int getMinWidth() {
		return minWidth;
	}

	public void setMinWidth(int minWidth) {
		this.minWidth = minWidth;
	}

	public int getMaxWidth() {
		return maxWidth;
	}

	public void setMaxWidth(int maxWidth) {
		this.maxWidth = maxWidth;
	}

	public String getPlaceholderName() {
		return placeholderName;
	}

	public void setPlaceholderName(String placeholderName) {
		this.placeholderName = placeholderName;
	}

	public String getModifier() {
		return modifier;
	}

	public void setModifier(String modifier) {
		this.modifier = modifier;
	}

	public void putProperty(String key, Object value) {
		properties.put(key, value);
	}

	@SuppressWarnings("unchecked")
	public <T> T getProperty(String key, Class<T> clazz) {
		return (T) properties.get(key);
	}

	@Override
	public String toString() {
		return "ConversionRule [modifier=" + modifier + ", placeholderName="   + placeholderName + "]";  
	}
public class ConversionRuleParser {

	private static final Pattern EXTRACTION_PATTERN = Pattern.compile("%(-?(\\d+))?(\\.(\\d+))?([a-zA-Z])(\\{([^\\}]+)\\})?"); 
	public static final String PROP_DATEFORMAT = "dateFormat";

	protected Pattern getInternalPattern(String externalPattern) throws Exception {
		List<ConversionRule> rules = extractRules(externalPattern);
		return Pattern.compile(toRegexPattern(prepare(externalPattern), rules));
	}
	
	protected List<ConversionRule> extractRules(String externalPattern) throws Exception {
		externalPattern = prepare(externalPattern);
		Matcher m = EXTRACTION_PATTERN.matcher(externalPattern);
		List<ConversionRule> ret = new ArrayList<ConversionRule>();
		while (m.find()) {
			String minWidthModifier = m.group(2);
			String maxWidthModifier = m.group(4);
			String conversionName = m.group(5);
			String conversionModifier = m.group(7);
			int minWidth = -1;
			if ((minWidthModifier != null) && (minWidthModifier.length() > 0)) {
				minWidth = Integer.parseInt(minWidthModifier);
			}
			int maxWidth = -1;
			if ((maxWidthModifier != null) && (maxWidthModifier.length() > 0)) {
				maxWidth = Integer.parseInt(maxWidthModifier);
			}
			ConversionRule rule = new ConversionRule();
			rule.setBeginIndex(m.start());
			rule.setLength(m.end() - m.start());
			rule.setMaxWidth(maxWidth);
			rule.setMinWidth(minWidth);
			rule.setPlaceholderName(conversionName);
			rule.setModifier(conversionModifier);
			rewrite(rule);
			ret.add(rule);
		}
		return ret;
	}

	public String prepare(String externalPattern) throws Exception {
		if (!externalPattern.endsWith("%n")) { 
			return externalPattern;
		}
		// Pattern without %n
		externalPattern = externalPattern.substring(0, externalPattern.length() - 2);
		if (externalPattern.contains("%n")) { 
			throw new Exception("ConversionPattern不合法!");
		}
		return externalPattern;
	}
	
	private void rewrite(ConversionRule rule) throws Exception {
		if (rule.getPlaceholderName().equals("d")) {
			applyDefaults(rule);
			if (rule.getModifier().equals("ABSOLUTE")) {
				rule.setModifier("HH:mm:ss,SSS");
			} else if (rule.getModifier().equals("DATE")) {
				rule.setModifier("dd MMM yyyy HH:mm:ss,SSS");
			} else if (rule.getModifier().equals("ISO8601")) {
				rule.setModifier("yyyy-MM-dd HH:mm:ss,SSS");
			}
			try {
				// Cache date format
				rule.putProperty(PROP_DATEFORMAT, new SimpleDateFormat(rule.getModifier()));
			} catch (IllegalArgumentException e) {
				throw new Exception(e);
			}
		}
	}

	private void applyDefaults(ConversionRule rule) throws Exception {
		if (rule.getModifier() == null) {
			// ISO8601 is the default
			rule.setModifier("ISO8601");
		}
	}

	private String getRegexPatternForRule(ConversionRule rule) throws Exception {
		if (rule.getPlaceholderName().equals("d")) {
			// Pattern is dynamic
			return "(" + RegexUtils.getRegexForSimpleDateFormat(rule.getModifier()) + ")";
		} else if (rule.getPlaceholderName().equals("p")) {
			String lnHint = RegexUtils.getLengthHint(rule);
			if (lnHint.length() > 0) {
				return "([ A-Z]" + lnHint + ")";
			}
			// Default: Length is limited by the levels available
			return "([A-Z]{4,5})";
		} else if (rule.getPlaceholderName().equals("c")) {
			return "(.*" + RegexUtils.getLengthHint(rule) + RegexUtils.getLazySuffix(rule) + ")";
		} else if (rule.getPlaceholderName().equals("t")) {
			return "(.*" + RegexUtils.getLengthHint(rule) + RegexUtils.getLazySuffix(rule) + ")";
		} else if (rule.getPlaceholderName().equals("m")) {
			return "(.*" + RegexUtils.getLengthHint(rule) + RegexUtils.getLazySuffix(rule) + ")";
		} else if (rule.getPlaceholderName().equals("F")) {
			return "(.*" + RegexUtils.getLengthHint(rule) + RegexUtils.getLazySuffix(rule) + ")";
		} else if (rule.getPlaceholderName().equals("C")) {
			return "(.*" + RegexUtils.getLengthHint(rule) + RegexUtils.getLazySuffix(rule) + ")";
		} else if (rule.getPlaceholderName().equals("M")) {
			return "(.*" + RegexUtils.getLengthHint(rule) + RegexUtils.getLazySuffix(rule) + ")";
		} else if (rule.getPlaceholderName().equals("L")) {
			return "([0-9]*" + RegexUtils.getLengthHint(rule) + ")";
		} else if (rule.getPlaceholderName().equals("x")) {
			return "(.*" + RegexUtils.getLengthHint(rule) + RegexUtils.getLazySuffix(rule) + ")";
		}  
		throw new Exception("无法找到对应的表达式描述!");
	}

	protected String toRegexPattern(String externalPattern, List<ConversionRule> rules) throws Exception {
		// Determine whether rules are followed by quoted string, allowing use of special Regex lazy modifiers
		int idx = 0;
		ConversionRule prevRule = null;
		for (ConversionRule rule : rules) {
			if ((rule.getBeginIndex() > idx) && (prevRule != null)) {
				// Previous rule is followed by a quoted string, allowing special regex flags
				prevRule.setFollowedByQuotedString(true);
			}
			idx = rule.getBeginIndex();
			idx += rule.getLength();
			prevRule = rule;
		}
		if ((externalPattern.length() > idx) && (prevRule != null)) {
			// Previous rule is followed by a quoted string, allowing special regex flags
			prevRule.setFollowedByQuotedString(true);
		}
		// Build the internal Regex pattern
		StringBuilder sb = new StringBuilder();
		idx = 0;
		for (ConversionRule rule : rules) {
			if (rule.getBeginIndex() > idx) {
				// Escape chars with special meaning
				sb.append(Pattern.quote(externalPattern.substring(idx, rule.getBeginIndex())));
			}
			idx = rule.getBeginIndex();
			String regex = this.getRegexPatternForRule(rule);
			sb.append(regex);
			idx += rule.getLength();
		}
		if (externalPattern.length() > idx) {
			// Append suffix
			sb.append(Pattern.quote(externalPattern.substring(idx)));
		}
		return sb.toString();
	}
}

 

 

 

public class ConversionPatternParser {

	private Map<String, Appender> appenderBag;
	public static String CONVERSION_JUST_4TEST = "%d [] %-5p %c{2} - %m%n";

	public ConversionPatternParser() {}

	public void parseConfiguration(String configFilePath) throws Exception {
		AppenderParser config = new AppenderParser();
		config.parse(configFilePath);
		setAppenderBag(config.getAppenderBag());
	}

	public String getConversionPattern(Appender appender) {
		Layout layout = appender.getLayout();
		if (layout instanceof PatternLayout) {
			PatternLayout patternLayout = (PatternLayout) layout;
			return patternLayout.getConversionPattern();
		}
		return null;
	}

	public void setAppenderBag(Map<String, Appender> appenderBag) {
		this.appenderBag = appenderBag;
	}

	public Map<String, Appender> getAppenderBag() {
		return appenderBag;
	}
}
/**
 * @author Philipp Nanz
 */
public class RegexUtils {

	private static transient Logger logger = LoggerFactory.getLogger(RegexUtils.class);

	/**
	 * Returns the Regex lazy suffix for the given rule.
	 * @param rule the conversion rule
	 * @return the Regex lazy suffix
	 */
	public static String getLazySuffix(ConversionRule rule) {
		if (rule.isFollowedByQuotedString()) {
			return "?";
		} else {
			return "";
		}
	}

	/**
	 * Returns the Regex length hint for the given rule.
	 * @param rule the conversion rule
	 * @return the Regex length hint
	 */
	public static String getLengthHint(ConversionRule rule) {
		if ((rule.getMaxWidth() > 0) && (rule.getMaxWidth() == rule.getMinWidth())) {
			// Exact length specified
			return "{" + rule.getMaxWidth() + "}";
		} else if (rule.getMaxWidth() > 0) {
			// Both min and max are specified
			return "{" + Math.max(0, rule.getMinWidth()) + "," + rule.getMaxWidth() + "}"; //$NON-NLS-3$
		} else if (rule.getMinWidth() > 0) {
			// Only min is specified
			return "{" + rule.getMinWidth() + ",}";
		}
		return "";
	}

	/**
	 * Converts a given <code>java.lang.SimpleDateFormat</code> pattern into 
	 * a regular expression
	 * @param format the pattern
	 * @return the translated pattern
	 * @throws Exception if an error occurred
	 */
	public static String getRegexForSimpleDateFormat(String format) throws Exception {
		RegexUtils utils = new RegexUtils();
		return utils.doGetRegexForSimpleDateFormat(format);
	}

	private String doGetRegexForSimpleDateFormat(String format) throws Exception {
		try {
			new SimpleDateFormat(format);
		} catch (Exception e) {
			// Pattern is invalid
			throw new Exception(e);
		}
		// Initialize
		ReplacementContext ctx = new ReplacementContext();
		ctx.setBits(new BitSet(format.length()));
		ctx.setBuffer(new StringBuffer(format));
		// Unquote
		unquote(ctx);
		// G - Era designator
		replace(ctx, "G+", "[ADBC]{2}");
		// y - Year
		replace(ctx, "[y]{3,}", "\\d{4}");
		replace(ctx, "[y]{2}", "\\d{2}");
		replace(ctx, "y", "\\d{4}");
		// M - Month in year
		replace(ctx, "[M]{3,}", "[a-zA-Z]*");
		replace(ctx, "[M]{2}", "\\d{2}");
		replace(ctx, "M", "\\d{1,2}");
		// w - Week in year
		replace(ctx, "w+", "\\d{1,2}");
		// W - Week in month
		replace(ctx, "W+", "\\d");
		// D - Day in year
		replace(ctx, "D+", "\\d{1,3}");
		// d - Day in month
		replace(ctx, "d+", "\\d{1,2}");
		// F - Day of week in month
		replace(ctx, "F+", "\\d");
		// E - Day in week
		replace(ctx, "E+", "[a-zA-Z]*");
		// a - Am/pm marker
		replace(ctx, "a+", "[AMPM]{2}");
		// H - Hour in day (0-23)
		replace(ctx, "H+", "\\d{1,2}");
		// k - Hour in day (1-24)
		replace(ctx, "k+", "\\d{1,2}");
		// K - Hour in am/pm (0-11)
		replace(ctx, "K+", "\\d{1,2}");
		// h - Hour in am/pm (1-12)
		replace(ctx, "h+", "\\d{1,2}");
		// m - Minute in hour
		replace(ctx, "m+", "\\d{1,2}");
		// s - Second in minute
		replace(ctx, "s+", "\\d{1,2}");
		// S - Millisecond
		replace(ctx, "S+", "\\d{1,3}");
		// z - Time zone
		replace(ctx, "z+", "[a-zA-Z-+:0-9]*");
		// Z - Time zone
		replace(ctx, "Z+", "[-+]\\d{4}");
		return ctx.getBuffer().toString();
	}

	private void unquote(ReplacementContext ctx) {
		Pattern p = Pattern.compile("'[^']+'");
		Matcher m = p.matcher(ctx.getBuffer().toString());
		while (m.find()) {
			logger.trace(ctx.toString());
			// Match is valid
			int offset = -2;
			// Copy all bits after the match
			for (int i = m.end(); i < ctx.getBuffer().length(); i++) {
				ctx.getBits().set(i + offset, ctx.getBits().get(i));
			}
			for (int i = m.start(); i < m.end() + offset; i++) {
				ctx.getBits().set(i);
			}
			ctx.getBuffer().replace(m.start(), m.start() + 1, "");
			ctx.getBuffer().replace(m.end() - 2, m.end() - 1, "");
			logger.trace(ctx.toString());
		}
		p = Pattern.compile("''");
		m = p.matcher(ctx.getBuffer().toString());
		while (m.find()) {
			logger.trace(ctx.toString());
			// Match is valid
			int offset = -1;
			// Copy all bits after the match
			for (int i = m.end(); i < ctx.getBuffer().length(); i++) {
				ctx.getBits().set(i + offset, ctx.getBits().get(i));
			}
			for (int i = m.start(); i < m.end() + offset; i++) {
				ctx.getBits().set(i);
			}
			ctx.getBuffer().replace(m.start(), m.start() + 1, "");
			logger.trace(ctx.toString());
		}
	}

	private void replace(ReplacementContext ctx, String regex, String replacement) {
		Pattern p = Pattern.compile(regex);
		Matcher m = p.matcher(ctx.getBuffer().toString());
		while (m.find()) {
			logger.trace(regex);
			logger.trace(ctx.toString());
			int idx = ctx.getBits().nextSetBit(m.start());
			if ((idx == -1) || (idx > m.end() - 1)) {
				// Match is valid
				int len = m.end() - m.start();
				int offset = replacement.length() - len;
				if (offset > 0) {
					// Copy all bits after the match, in reverse order
					for (int i = ctx.getBuffer().length() - 1; i > m.end(); i--) {
						ctx.getBits().set(i + offset, ctx.getBits().get(i));
					}
				} else if (offset < 0) {
					// Copy all bits after the match
					for (int i = m.end(); i < ctx.getBuffer().length(); i++) {
						ctx.getBits().set(i + offset, ctx.getBits().get(i));
					}
				}
				for (int i = m.start(); i < m.end() + offset; i++) {
					ctx.getBits().set(i);
				}
				ctx.getBuffer().replace(m.start(), m.end(), replacement);
				logger.trace(ctx.toString());
			}
		}
	}

	private class ReplacementContext {

		private BitSet bits;
		private StringBuffer buffer;

		/**
		 * @return the bits
		 */
		public BitSet getBits() {
			return bits;
		}

		/**
		 * @param bits the bits to set
		 */
		public void setBits(BitSet bits) {
			this.bits = bits;
		}

		/**
		 * @return the buffer
		 */
		public StringBuffer getBuffer() {
			return buffer;
		}

		/**
		 * @param buffer the buffer to set
		 */
		public void setBuffer(StringBuffer buffer) {
			this.buffer = buffer;
		}

		/*
		 * (non-Javadoc)
		 * @see java.lang.Object#toString()
		 */
		@Override
		public String toString() {
			StringBuffer sb = new StringBuffer();
			sb.append("ReplacementContext [bits=");
			for (int i = 0; i < buffer.length(); i++) {
				sb.append(bits.get(i) ? '1' : '0');
			}
			sb.append(", buffer=");
			sb.append(buffer);
			sb.append(']');
			return sb.toString();
		}
	}
}
public class LogEntry {
	
	private Map<String, Object> map = new HashMap<String, Object>();
	 
	public final <VT> void put(String key, VT value) {
		map.put(key, value);
	}
 
	@SuppressWarnings("unchecked")
	public final <VT> VT get(String key) {
		return (VT) map.get(key);
	}
 
	public final <VT> boolean contains(String key) {
		return map.containsKey(key);
	}
	
	public String toString() {
		return map.toString();
	}
}
 

 

 

public class LogFileParser {

	public static final String FIELD_LOGGER = "logger";
	public static final String FIELD_TIMESTAMP = "timestamp";
	public static final String FIELD_LEVEL = "level";
	public static final String FIELD_THREAD = "thread";
	public static final String FIELD_MESSAGE = "message";
	public static final String FIELD_CURRENT_LINE = "currLine";
	public static final String FIELD_IS_HIT = "isHit";
	public static final String FIELD_NDC = "ndc";
	public static final String FIELD_THROWABLE = "throwable";
	public static final String FIELD_LOC_FILENAME = "locFilename";
	public static final String FIELD_LOC_CLASS = "locClass";
	public static final String FIELD_LOC_METHOD = "locMethod";
	public static final String FIELD_LOC_LINE = "locLine";
	private static Logger logger = Logger.getLogger(LogFileParser.class);
	private ConversionRuleParser conversionRuleParser;

	public LogFileParser() {
		conversionRuleParser = new ConversionRuleParser();
	}

	public List<LogEntry> parse(String fileName, String conversionPattern, String content, Integer upperLogNum, Integer lowerLogNum) throws Exception {
		List<ConversionRule> extractRules = conversionRuleParser.extractRules(conversionPattern);
		FileInputStream fis = new FileInputStream(new File(fileName));
		LineIterator iter = IOUtils.lineIterator(fis, "GBK");
		try {
			List<LogEntry> logLines = iterateLogLines(conversionPattern, extractRules, iter, upperLogNum, lowerLogNum, content);
			return logLines;
		} finally {
			LineIterator.closeQuietly(iter);
		}
	}

	@SuppressWarnings("unchecked")
	private List<LogEntry> iterateLogLines(String conversionPattern, List<ConversionRule> extractRules, LineIterator iter, Integer upperLogNum, Integer lowerLogNum, String content) throws Exception {
		boolean flag = true;
		List<LogEntry> result = new ArrayList<LogEntry>();
		BoundedFifoBuffer upperLogEntries = null;
		if (upperLogNum != null && upperLogNum > 0)
		    upperLogEntries = new BoundedFifoBuffer(upperLogNum);
		BoundedFifoBuffer lowerLogEntries = null;
		if (lowerLogNum != null && lowerLogNum > 0)
		    lowerLogEntries = new BoundedFifoBuffer(lowerLogNum);
		LogEntry unfinishedEntry = null;
		LogEntry currentEntry = fetchARecord(iter, conversionPattern, extractRules, unfinishedEntry);
		while (currentEntry != null) {
			String msg = currentEntry.get(FIELD_MESSAGE);
			boolean isHit = msg.contains(content);
			if (flag) {
				if (isHit) {
					//命中
					flag = false;
					if (upperLogEntries != null) {
						result.addAll(upperLogEntries);
						upperLogEntries.clear();
					}
					currentEntry.put(FIELD_IS_HIT, true);
					result.add(currentEntry);
				} else {
					if (upperLogEntries != null) {
						if (upperLogEntries.isFull()) {
							upperLogEntries.remove();
						}
						upperLogEntries.add(currentEntry);
					}
				}
				currentEntry = fetchARecord(iter, conversionPattern, extractRules, unfinishedEntry);
				continue;
			} else {
				if (!isHit) {
					if (lowerLogNum != 0) {
						//未命中
						if (lowerLogEntries != null) {
							lowerLogEntries.add(currentEntry);
							if (lowerLogEntries.isFull()) {
								//转移Lower中的记录到LogList中
								flag = true;
								result.addAll(lowerLogEntries);
								lowerLogEntries.clear();
							}
						}
					} else {
						flag = true;
					}
				} else {
					if (lowerLogEntries != null) {
						result.addAll(lowerLogEntries);
						lowerLogEntries.clear();
					}
					currentEntry.put(FIELD_IS_HIT, true);
					result.add(currentEntry);
				}
				currentEntry = fetchARecord(iter, conversionPattern, extractRules, unfinishedEntry);
				continue;
			}
		}
		return result;
	}

	private long lineNo = 1;

	private LogEntry fetchARecord(LineIterator iter, String conversionPattern, List<ConversionRule> extractRules, LogEntry unfinishedEntry) throws Exception {
		LogEntry currentEntry = null;
		boolean found = true;
		if (unfinishedEntry == null) {
			found = false;
		}
		if (!iter.hasNext()) {
			return null;
		}
		while (iter.hasNext()) {
			// Error handling 
			String line = iter.nextLine();
			while (StringUtils.isBlank(line) && iter.hasNext()) {
				line = iter.nextLine();
			}
			Matcher m = conversionRuleParser.getInternalPattern(conversionPattern).matcher(line);
			if (m.find()) {
				//It's next entry, unfinished
				if (found) {
					currentEntry = unfinishedEntry;
					unfinishedEntry = new LogEntry();
					for (int i = 0; i < m.groupCount(); i++) {
						try {
							this.extractField(unfinishedEntry, extractRules.get(i), m.group(i + 1));
						} catch (Exception e) {
							// Mark for interruption 
							logger.warn(e);
						}
					}
					currentEntry.put(FIELD_CURRENT_LINE, lineNo++);
					return currentEntry;
				} else {
					unfinishedEntry = new LogEntry();
					found = true;
					for (int i = 0; i < m.groupCount(); i++) {
						try {
							this.extractField(unfinishedEntry, extractRules.get(i), m.group(i + 1));
						} catch (Exception e) {
							// Mark for interruption 
							logger.warn(e);
						}
					}
				}
			} else if (unfinishedEntry != null) {
				String msg = unfinishedEntry.get(FIELD_MESSAGE);
				msg += '\n' + line;
				unfinishedEntry.put(FIELD_MESSAGE, msg);
			}
		}
		if (unfinishedEntry != null) {
			currentEntry = unfinishedEntry;
		}
		if (currentEntry != null)
		    currentEntry.put(FIELD_CURRENT_LINE, lineNo++);
		return currentEntry;
	}

	private void extractField(LogEntry entry, ConversionRule rule, String val) throws Exception {
		if (rule.getPlaceholderName().equals("d")) {
			DateFormat df = rule.getProperty(ConversionRuleParser.PROP_DATEFORMAT, DateFormat.class);
			entry.put(FIELD_TIMESTAMP, df.parse(val.trim()));
		} else if (rule.getPlaceholderName().equals("p")) {
			Level lvl = Level.toLevel(val.trim());
			entry.put(FIELD_LEVEL, lvl);
		} else if (rule.getPlaceholderName().equals("c")) {
			entry.put(FIELD_LOGGER, val.trim());
		} else if (rule.getPlaceholderName().equals("t")) {
			entry.put(FIELD_THREAD, val.trim());
		} else if (rule.getPlaceholderName().equals("m")) {
			entry.put(FIELD_MESSAGE, val.trim());
		} else if (rule.getPlaceholderName().equals("F")) {
			entry.put(FIELD_LOC_FILENAME, val.trim());
		} else if (rule.getPlaceholderName().equals("C")) {
			entry.put(FIELD_LOC_CLASS, val.trim());
		} else if (rule.getPlaceholderName().equals("M")) {
			entry.put(FIELD_LOC_METHOD, val.trim());
		} else if (rule.getPlaceholderName().equals("L")) {
			entry.put(FIELD_LOC_LINE, val.trim());
		} else if (rule.getPlaceholderName().equals("x")) {
			entry.put(FIELD_NDC, val.trim());
		} else {
			throw new Exception("异常消息暂未设置");
		}
	}
}

LogFileParser的活动图:

活动图

 

public class AppenderParser extends DOMConfigurator {

	private Map<String, Appender> appenderBag = new HashMap<String, Appender>();
	private Document doc = null;
	private DocumentBuilderFactory dbf;
	private DocumentBuilder db = null;

	public AppenderParser() {}

	public void parse(String configFile) throws Exception {
		doc = getDocument(configFile);
		NodeList appenderList = doc.getElementsByTagName("appender");
		for (int t = 0; t < appenderList.getLength(); t++) {
			Node node = appenderList.item(t);
			NamedNodeMap map = node.getAttributes();
			Node attrNode = map.getNamedItem("name");
			if (getAppenderBag().get(attrNode.getNodeValue()) == null) {
				Appender appender = parseAppender((Element) node);
				getAppenderBag().put(attrNode.getNodeValue(), appender);
			}
		}
	}

	private Document getDocument(String configFile) throws ParserConfigurationException, SAXException, IOException {
		dbf = DocumentBuilderFactory.newInstance();
		db = dbf.newDocumentBuilder();
		return db.parse(new File(configFile));
	}
	
	public static void main(String[] args) throws Exception {
		String configFile = "D:\\log4j.xml";
	    AppenderParser config = new AppenderParser();
		config.parse(configFile);
		System.out.println(SerializeUtil.serialize(config.getAppenderBag()));
    }

	public void setAppenderBag(Map<String, Appender> appenderBag) {
	    this.appenderBag = appenderBag;
    }

	public Map<String, Appender> getAppenderBag() {
	    return appenderBag;
    }
}
@Component
public class LoggerSearch {

	private AppenderParser appenderParser;
	private LogFileParser logParser;
	private Map<String, Appender> appenders;
	private String configFilePath = "log4j.xml";
	List<LogEntry> logEntries;
	Map<String, List<LogEntry>> allLogEntries;

	@PostConstruct
	public void init() throws Exception {
		appenderParser = new AppenderParser();
		logParser = new LogFileParser();
		appenderParser.parse(getConfigFilePath());
		appenders = appenderParser.getAppenderBag();
		allLogEntries = new HashMap<String, List<LogEntry>>();
	}

	public Map<String, List<LogEntry>> searchAll(String content, Integer upperLogNum, Integer lowerLogNum) throws Exception {
		for (Appender appender : appenders.values()) {
			if (appender instanceof FileAppender) {
				FileAppender fileAppender = (FileAppender) appender;
				if (appender instanceof DailyRollingFileAppender) {
					Layout layout = fileAppender.getLayout();
					if (layout instanceof PatternLayout) {
						PatternLayout patternLayout = (PatternLayout) layout;
						String conversionPattern = patternLayout.getConversionPattern();
						String fileName = fileAppender.getFile();
						logEntries = logParser.parse(fileName, conversionPattern, content, upperLogNum, lowerLogNum);
						allLogEntries.put(new File(fileName).getName(), logEntries);
					}
				}
			}
		}
		return allLogEntries;
	}

	public void setConfigFilePath(String configFilePath) {
		this.configFilePath = configFilePath;
	}

	public String getConfigFilePath() {
		return LoggerSearch.class.getClassLoader().getResource(configFilePath).getFile();
	}
}

 

 

上述部分代码参考了LogSaw,其中仅实现了简单的功能,如果有需要可自行扩展。

另附上一个JMX查询接口:

 

@Component
@JmxClass
public class Log4jGrep {

	@Resource
	private LoggerSearch loggerSearch;

	@JmxMethod
	public String searchAll(String content, Integer upperLogNum, Integer lowerLogNum) {
		try {
			StringBuilder sb = new StringBuilder();
			Map<String, List<LogEntry>> logEntries = loggerSearch.searchAll(content, upperLogNum, lowerLogNum);
			String color = "#cccccc";
			for (String logName : logEntries.keySet()) {
				List<LogEntry> logs = logEntries.get(logName);
				if (logs != null && logs.size() > 0) {
					sb.append("<p style=\"\font-weight: bold;color: #FF0000;font-family: Geneva, Arial, Helvetica, sans-serif;font-size: x-large;\">" + logName + "</p>");
					sb.append("<table height=\"100\" border=\"1\">");
					sb.append("<tr>");
					sb.append("<td width=\"45\">行号</td>");
					sb.append("<td width=\"55\">等级</td>");
					sb.append("<td width=\"88\">类名</td>");
					sb.append("<td width=\"763\">信息</td>");
					sb.append("</tr>");
					for (LogEntry log : logs) {
						if (log.get(LogFileParser.FIELD_IS_HIT) != null) {
							color = "#cccccc";
						} else {
							color = "";
						}
						sb.append("<tr bgcolor=" + color + ">");
						sb.append("<td>" + log.get(LogFileParser.FIELD_CURRENT_LINE) + "</td>");
						sb.append("<td>" + log.get(LogFileParser.FIELD_LEVEL) + "</td>");
						sb.append("<td>" + log.get(LogFileParser.FIELD_LOGGER) + "</td>");
						String msg = log.get(LogFileParser.FIELD_MESSAGE);
						msg = msg.replaceAll(content, "<span style=\"color: #FFFFFF;background: #FF0000;\">" + content + "</span>");
						sb.append("<td style=\"word-wrap:break-word;\">" + msg + "</td>");
						sb.append("</tr>");
					}
					sb.append("<table/>");
				}
			}
			return sb.toString();
		} catch (Exception e) {
			return ExceptionUtils.getFullStackTrace(e);
		}
	}
}
3
1
分享到:
评论
1 楼 blueman2012 2014-11-20  
您好,可否提供源码下载,我把您的代码贴过来后,好多报错的,谢谢了。

相关推荐

    javaweb配置Log4j发送日志邮件------全面

    javaweb配置Log4j发送日志邮件, 简单例子解析------只起到一个抛砖引玉的作用.有什么意见请多多指出...不足之处望请见谅

    Log Viewer(日志查看器)

    Java Log Viewer(日志查看器)能够自定义log表达式,具备的功能包括: 1.可以手动重载日志。这样既可以防止自动跟踪...9.预设对多种格式日志的支持,并且有一个编辑器方便自定义需解析的Log4j日志模式(pattern)。

    spring+springmvc+mybatis+结合前端easyUI框架,log4j日志文件配置

    本项目使用前端技术结合easyUI,后端使用spring+springmvc+mybatis,log4j日志文件配置(带注释解析)

    log4j2 自动删除过期日志文件的配置及实现原理

    主要介绍了log4j2 自动删除过期日志文件配置及实现原理解析,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下

    Log Viewer日志查看器

    Java Log Viewer(日志查看器)能够自定义log表达式,具备的功能包括: 1.可以手动重载日志。这样既可以防止自动跟踪...9.预设对多种格式日志的支持,并且有一个编辑器方便自定义需解析的Log4j日志模式(pattern)。

    Log4j日志记录框架配置及用法解析

    主要介绍了Log4j日志记录框架配置及用法解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下

    jdom+log4j jar包

    通过使用Log4j,我们可以控制日志信息输送的目的地是控制台、文件、GUI组件、甚至是套接口服务器、NT的事件记录器、UNIX Syslog守护进程等;我们也可以控制每一条日志的输出格式;通过定义每一条日志信息的级别,...

    Tomcat使用Log4j输出catalina.out日志

    日志格式和项目中用log4j打出来的不一致,不利于解析。 从tomcat官网(https://tomcat.apache.org/tomcat-7.0-doc/logging.html)上找了下,修改一些配置、替换扩展包即可使用log4j输出catalian.out。 在$CATALINA_...

    详细解析_Log4j_配置

    Log4j有三个主要的组件:Loggers(记录器),Appenders (输出源)和Layouts(布局)。这里可简单理解为日志类别,日志要输出的地方和日志以何种形式输出。综合使用这三个组件可以轻松地记录信息的类型和级别,并可以在...

    log4j使用详细解析

    Log4j 除了可以记录程序运行日志信息外还有一重要的功能就是用来显示调试信息。下面通过本文给大家介绍log4j使用详细解析,感兴趣的朋友一起看看吧

    解决因缺少Log4j依赖导致应用启动失败的问题

    日志是应用软件中不可缺少的部分,Apache的开源项目log4j是一个功能强大的日志组件,提供方便的日志记录。但这篇文章不是介绍Log4j,这篇文章主要介绍了关于因缺少Log4j依赖导致应用启动失败问题的相关资料,需要的...

    java日志框架视频教程

    Log4j组件解析3. Layout格式4. Appender输出5. 自定义Logger章节四:JCL1. 快速入门2. 原理解析章节五:Slf4j1. 快速入门2. 绑定日志实现3. 桥接旧日志实现4. 原理解析章节六:Logback1. 快速入门2. 配置文件3. ...

    Java日志体系全解析:架构师必掌握的关键技术和最佳实践

    最初,log4j作为早期流行的日志框架,广泛应用于Java项目中。然而,随着Java平台的发展,出现了多种日志框架,如JUL(java.util.logging)和JCL(Jakarta Commons Logging),这增加了选择和维护的复杂性。JCL作为一...

    simple-log-analyzer:简单的日志分析器。 log4j 解析器 --&gt; 便于搜索的数据库等

    简单日志分析器简单的日志分析器。 log4j 解析器 --&gt; 便于搜索的数据库等

    log4j-aws-appenders:写入AWS目标的Log4J 1.2.x,Log4J 2.x和Logback的Appender

    log4j-aws-appenders , 和Appender写入了各种AWS目标: :AWS本地集中式日志管理,提供关键字和时间范围搜索。 :这是向和其他分析目标提供数据的第一步。 :用于实时错误通知。 除了基本的日志输出外,该库还...

    yarn-auditlog-parser:Yarn的hdfs-audit.log的日志文件解析,从ip,用户名,时间段维度对hdfs的qps量进行统计

    Yarn的hdfs-audit.log的日志文件解析,从ip,用户名,时间段维度对hdfs的qps量进行统计 原理介绍 此工具用于分析hdfs-audit日志文件中的hdfs请求,比如下面是一条完整的记录 2015-09-09 05:29:54,727 INFO ...

    log4j的使用详细解析

    最近在整理公司产品的日志输出规范,涉及log4j的使用介绍,就简单整理了一下。需要的朋友可以过来参考参考

    谷歌师兄的leetcode刷题笔记-LogParser:基于机器学习的日志解析器

    谷歌师兄的leetcode刷题笔记日志解析器 基于机器学习的日志解析器 数据集 日志大小 描述 来源 高密度文件系统 11197705 Hadoop 运行时日志 W. Xu、L. Huang、A. Fox、D. Patterson 和 MI Jordan,“通过挖掘控制台...

    SpringMVC 数据解析(Form/Ajax)

    1.SpringMVC框架, 2.使用MYSQL数据库分读、写; 3.使用Log4j日志 4.详解数据提交和解析 文档地址:http://blog.csdn.net/sandyagor/article/details/51016885

Global site tag (gtag.js) - Google Analytics