`

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  
您好,可否提供源码下载,我把您的代码贴过来后,好多报错的,谢谢了。

相关推荐

    log4j日志文件乱码解决方法

    本文将详细讨论如何解决Log4j日志文件出现的乱码问题。 首先,我们要理解Log4j的工作原理。Log4j允许开发者自定义日志输出的方式,包括输出到控制台、文件、数据库等。它使用了`QuietWriter`类来写入日志,`...

    无法打出log4j日志的问题排查

    当我们遇到“无法打出log4j日志的问题”,这通常是由于配置、环境或代码实现中的某些错误导致的。这篇长文将深入探讨如何排查和解决这类问题。 首先,我们要理解Log4j的基本工作原理。Log4j通过配置文件(通常是log...

    log4j(二):动态配置日志输出路径

    总结来说,Log4j的动态配置日志输出路径主要涉及对配置文件的解析和重新加载,以及在运行时使用API直接调整日志设置。理解并熟练运用这些方法,可以帮助我们在开发过程中更灵活地管理和监控日志,提高开发效率和问题...

    Kafka+Log4j实现日志集中管理

    在实际操作中,可能还需要结合其他工具,如Logstash用于日志解析和Elasticsearch进行日志存储与搜索,形成ELK(Elasticsearch, Logstash, Kibana)或EFK(Elasticsearch, Fluentd, Kibana)栈,以提供更强大的日志...

    log4j 日志打印jar

    《深入理解Log4j:构建高效...以上就是关于Log4j日志打印的全面解析,希望能对你自定义的日志记录工具提供有价值的参考和启示。在实际使用中,不断学习和实践,才能更好地发挥Log4j的优势,提升日志记录的质量和效率。

    配置Log4j的详细最好的日志工具

    ### 配置Log4j的详细指南:最佳的日志管理工具 #### 一、引言 在软件开发过程中,良好的日志记录对于调试、维护和性能优化等方面具有至关重要的作用。Log4j作为Apache下的一个开源项目,因其高度灵活性、易配置性...

    log4j-api-2.17.1.jar和log4j-core-2.17.1.jar

    这个库实现了log4j-api中定义的接口,提供了具体的功能,比如各种Appender(控制台输出、文件写入、网络传输等)、Layout(日志格式化)、Filter(日志过滤)和Lookup(动态配置变量解析)。例如,`org.apache....

    log4j 源码包 日志包 2.11.0

    《深入解析Log4j 2.11.0源码》 Log4j,作为Java领域最常用的日志框架之一,其2.11.0版本的发布为开发者提供了更加强大、高效和灵活的日志处理能力。源码包的获取,对于开发者深入理解其工作原理、定制化需求以及...

    log4j-API-最新稳定版本log4j-1.2.17

    标题提及的是"log4j-API-最新稳定版本log4j-1.2.17",这表明我们关注的是日志框架Log4j的一个特定版本,即1.2.17。Log4j是Apache软件基金会开发的一个用于Java应用程序的日志记录工具,它提供了灵活的日志记录功能,...

    log4j.zip 项目日志

    四、Log4j的使用 在Java代码中,我们可以使用以下方式创建和使用Logger: ```java import org.apache.log4j.Logger; public class MyClass { private static final Logger logger = Logger.getLogger(MyClass....

    log4j-2.11.2的jar包和日志门面slf4j的jar包

    在提供的`log4j-core-2.11.2.jar`和`log4j-api-2.11.2.jar`中,`log4j-core`是实现部分,包含了各种日志记录功能,如配置解析、日志事件的处理等;而`log4j-api`则包含API接口,供开发者在代码中调用,定义日志级别...

    教你更简单的使用log4j日志

    ### 教你更简单的使用log4j日志 在日常的软件开发过程中,日志记录是必不可少的一个环节,它能够帮助我们追踪程序运行时的状态、定位问题所在,并且为后期维护提供重要的参考依据。Log4j作为Apache组织下的一个开源...

    Log4j2、Fastjson、Log4j的BurpSuite插件亲测有效

    Log4j是Apache的一个开源项目,主要用于日志记录,提供了灵活的日志配置,允许开发者根据需求调整日志输出的级别和格式。Log4j2作为Log4j的升级版本,它在性能、可配置性和可扩展性上有了显著提升,同时也修复了Log4...

    日志组件-仿log4j的配置

    Log4j是一款广泛使用的Java日志框架,但有时候我们可能需要根据特定需求创建一个类似Log4j的配置系统。这篇博客“日志组件-仿log4j的配置”探讨了如何设计和实现一个模仿Log4j的日志解决方案。 首先,我们需要理解...

    log4j-2.18.0

    Log4Shell漏洞的核心在于log4j2的Lookup功能,该功能允许在日志消息中动态解析变量。攻击者可以利用此功能,将恶意的JNDI链接注入到日志记录中,当log4j2尝试解析这些链接时,就会执行攻击者控制的代码。由于很多...

    配置好log4j的eclipse简单工程,每天输出到一个日志文件中,该文件名为:“XXX_年月日时分.log”的形式

    在IT行业中,日志记录是系统调试、性能分析和故障排查的重要工具,而Log4j则是Java编程语言中广泛使用的日志框架之一。本工程基于Eclipse IDE,配置了一个简单的Log4j设置,实现了每天自动将日志输出到一个特定命名...

    log4j记录压缩日记

    "Log4j记录压缩日记" 指的是使用Log4j日志框架来记录并压缩日志文件。Log4j是Apache的一个开源项目,它为应用程序提供了灵活的日志记录功能,包括输出格式、日志级别管理以及日志文件的滚动策略等。在某些场景下,...

    log4j-1.2.15.jar

    本文将详细解析Log4j 1.2.15.jar这个版本的核心概念、使用方法以及重要特性。 一、Log4j简介 Log4j是由Apache软件基金会开发的一个开源日志组件,主要为Java应用程序提供日志服务。它的设计理念是让日志输出变得...

    logging-log4j2-log4j-2.15.0-rc2.zip

    《深入理解Log4j 2.15.0-rc2:日志处理的关键技术解析》 Log4j,作为Java领域广泛使用的日志记录框架,一直以来都是开发者们的重要工具。这次我们关注的是其最新版本——logging-log4j2-log4j-2.15.0-rc2。这个版本...

Global site tag (gtag.js) - Google Analytics