栏目分类:
子分类:
返回
终身学习网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
终身学习网 > IT > 软件开发 > 后端开发 > .Net

让日志带上颜色

.Net 更新时间:发布时间: 百科书网 趣学号
原理

让System.out和System.err打印出来的日志带上格式 格式如下

原理将待打印字符串添加格式头让输出流支持格式 字符串末尾添加清楚格式字符串

添加格式字串 33[[背景色;][前景色;][其他格式;]其他格式m

如33[30m 33[30;40;1m 33[1m; 33[33;43;1;3;51m
30-38 90-98代表前景色 40-48 100-108 代表背景色 1,3,4,7,921,51字体格式

清除格式字符串 33[m 字符串最后一定要加 否则后面打印的都有格式

public class ConsoleTest {
	@Test
	public void testPrintColor() {
		int start = 30,end = 38,num;
		String space = "  33[0m   ";
		for (int i = start; i < end; i++) {
			num = i;
			System.out.print("33["+num+";"+"1m "+num+space);
			num = i + 60;
			System.out.print("33["+num+";"+"1m "+num+space);
			num = i + 10;
			System.out.print("33["+num+";"+"1m "+num+space);
			num = i + 70;
			System.out.print("33["+num+";"+"1m "+num+space+"n");
		}

		Map codes = new HashMap<>(16);
		codes.put(1,"加粗");
		codes.put(3,"倾斜");
		codes.put(4,"下划线");
		codes.put(7,"灰色背景");
		codes.put(9,"删除线");
		codes.put(21,"粗下划线");
		codes.put(51,"方框");
		codes.forEach((code,name)->{
			System.out.print("33["+code+";"+"1m "+code+":"+name+space);
			System.out.print("  ");
		});
		System.out.println();

		System.out.print("33[1;3;4;9;51;33m哈哈33[0m ");
		System.out.print("33[4;9;51;33m哈哈33[0m ");
	}
}
ConsoleFont

封装字体格式

测试用例运行结果如下

测试用例如下

@Test
	public void testConsoleFont() {
		ConsoleFont.success().bindSystemOut();
		System.out.println("success green");
		ConsoleFont.generate().unbindSystemOut();
		System.out.println("success default");

		ConsoleFont.generate().setBackground(ConsoleFont.Color.PINK).bindSystemError();
		System.err.println("fail pink");
		ConsoleFont.generate().unbindSystemError();
		System.err.println("fail default");

		ConsoleFont font = ConsoleFont.generate().setForeground(ConsoleFont.Color.PINK)
				.setBox(true).setUnderLine(ConsoleFont.UnderLine.COMMON);
		String message = font.handleMessage("hello world!");
		System.out.println(message);
		message = font.setDeleteLine(true)
				.setUnderLine(ConsoleFont.UnderLine.BOLD)
				.handleMessage(message);
		message = ConsoleFont.success().handleMessage(message);
		// 6红色是因为System.error
		System.out.println(message);

		message = ConsoleFont.generate().setBox(true)
				.setDeleteLine(true).setUnderLine(ConsoleFont.UnderLine.BOLD)
				.handleMessage("head ") + message;
		System.out.println(message);

		String msg = ConsoleFont.generate().cleanFontCodeByHead(message);
		System.out.println(msg);

		message = ConsoleFont.generate().cleanFontCode(message);
		System.out.println(message);

		ConsoleFont success = ConsoleFont.success();
		message = "save load test";
		System.out.println(success.handleMessage(message));
		success.save();
		success.setBackground(ConsoleFont.Color.CYAN);
		System.out.println(success.handleMessage(message));
		success.load();
		System.out.println(success.handleMessage(message));

	}

代码片段 可点击上面的gitee链接查看最新代码

@SuppressWarnings("UnusedReturnValue")
public class ConsoleFont implements Cloneable{
	private static final String FONT_CODE_PREFIX = "33[";
	private static final String EMPTY_FONT_CODE = "";
	private static final String FONT_CODE_SUFFIX = "m";
	private static final String DELETE_LINE_CODE = "9;";
	private static final String BOX_CODE = "51;";
	private static final String BOLD_CODE = "1;";
	private static final String ITALIC_CODE = "3;";
	private static final String DEFAULT_FONT_CODE = "33[0m";

	private UnderLine underLine = UnderLine.NONE;
	private Color background = Color.NONE;
	private Color foreground = Color.NONE;
	private boolean box;
	private boolean deleteLine;
	private boolean bold;
	private boolean italic;

	private boolean modify;

	private String fontCode;

	private ConsoleFont origin;

	private ConsoleFont(){
	}

	//---------------------------------------------------------
	// 业务方法
	//---------------------------------------------------------

	
	public ConsoleFont save(){
		origin = (ConsoleFont) this.clone();
		return this;
	}

	
	public ConsoleFont load(){
		if(origin == null){
			return this;
		}
		underLine = origin.underLine;
		foreground = origin.foreground;
		background = origin.background;
		box = origin.box;
		deleteLine = origin.deleteLine;
		bold = origin.bold;
		italic = origin.italic;
		modify = origin.modify;
		fontCode = origin.fontCode;
		return this;
	}

	@Override
	public Object clone() {
		try {
			return super.clone();
		} catch (CloneNotSupportedException e) {
			throw new RuntimeException(e);
		}
	}

	
	public String handleMessage(String message){
		message = cleanFontCodeByHead(message);
		String fontCode = getFontCode();
		if(fontCode.equals(EMPTY_FONT_CODE)){
			return message;
		}
		int capacity = fontCode.length() + message.length() + DEFAULT_FONT_CODE.length();
		//noinspection StringBufferReplaceableByString
		return new StringBuilder(capacity)
				.append(fontCode)
				.append(message)
				.append(DEFAULT_FONT_CODE)
				.toString();
	}

	
	public String cleanFontCodeByHead(String message) {
		if(isBlank(message)){
			return message;
		}
		while (message.startsWith(FONT_CODE_PREFIX)){
			int index = message.indexOf(FONT_CODE_SUFFIX);
			if(index > 0){
				message = message.substring(index+1);
			}
		}
		while (message.startsWith(DEFAULT_FONT_CODE)){
			message = message.substring(DEFAULT_FONT_CODE.length());
		}
		return message;
	}

	
	public String cleanFontCode(String message) {
		if(isBlank(message)){
			return message;
		}
		message = message.replaceAll("33\[.+?m", "");
		return message;
	}

	
	public ConsoleFont bindSystemOut(){
		print(System.out,getFontCode());
		return this;
	}

	
	public ConsoleFont unbindSystemOut(){
		print(System.out,DEFAULT_FONT_CODE);
		return this;
	}

	
	public ConsoleFont bindSystemError(){
		print(System.err,getFontCode());
		return this;
	}

	
	public ConsoleFont unbindSystemError(){
		print(System.err,DEFAULT_FONT_CODE);
		return this;
	}

	//---------------------------------------------------------
	// 实例构建方法
	//---------------------------------------------------------

	public static ConsoleFont generate(){
		return new ConsoleFont();
	}

	public static ConsoleFont success(){
		return ConsoleFont.generate().setForeground(Color.GREEN);
	}

	public static ConsoleFont error(){
		return ConsoleFont.generate().setForeground(Color.RED);
	}


	//---------------------------------------------------------
	// setter方法
	//---------------------------------------------------------

	public ConsoleFont setUnderLine(UnderLine underLine){
		this.underLine = underLine;
		return changed();
	}

	public ConsoleFont setDeleteLine(boolean deleteLine) {
		this.deleteLine = deleteLine;
		return changed();
	}

	public ConsoleFont setBox(boolean box) {
		this.box = box;
		return changed();
	}

	public ConsoleFont setBold(boolean bold) {
		this.bold = bold;
		return changed();
	}

	public ConsoleFont setItalic(boolean italic) {
		this.italic = italic;
		return changed();
	}

	public ConsoleFont setBackground(Color background) {
		Objects.requireNonNull(background);
		this.background = background;
		return changed();
	}

	public ConsoleFont setForeground(Color foreground) {
		Objects.requireNonNull(foreground);
		this.foreground = foreground;
		return changed();
	}

	//---------------------------------------------------------
	// 业务逻辑私有方法
	//---------------------------------------------------------

	private boolean isBlank(String message) {
		return message == null || message.trim().length() == 0;
	}

	private void print(PrintStream ps, String fontCode) {
		ps.print(fontCode);
	}

	private String getFontCode(){
		if(modify || fontCode == null){
			fontCode = calculateFontCode();
		}
		return fontCode;
	}

	private String calculateFontCode() {
		return generateBuilder().map(builder -> {
			builder.append(FONT_CODE_PREFIX)
					.append(background.getBackgroundCode())
					.append(foreground.getForegroundCode())
					.append(underLine.getCode());
			if (box) {
				builder.append(BOX_CODE);
			}
			if (deleteLine) {
				builder.append(DELETE_LINE_CODE);
			}
			if (bold){
				builder.append(BOLD_CODE);
			}
			if (italic){
				builder.append(ITALIC_CODE);
			}
			builder.deleteCharAt(builder.length() - 1);
			builder.append(FONT_CODE_SUFFIX);
			return builder.toString();
		}).orElse(EMPTY_FONT_CODE);
	}

	private Optional generateBuilder() {
		int len = calculateFontCodeLen();
		StringBuilder builder = len == 0 ? null : new StringBuilder(len);
		return Optional.ofNullable(builder);
	}

	private int calculateFontCodeLen() {
		int len = underLine.getLen() + background.getLen() + foreground.getLen();
		len += box ? BOX_CODE.length() : 0;
		len += deleteLine ? DELETE_LINE_CODE.length() : 0;
		len += bold ? BOLD_CODE.length() : 0;
		len += italic ? ITALIC_CODE.length() : 0;
		// 无需加上FONT_CODE_SUFFIX的len 因为要干掉一个; 刚好抵消
		len += len == 0 ? 0 : len + FONT_CODE_PREFIX.length();
		return len;
	}

	private ConsoleFont changed(){
		modify = true;
		return this;
	}

	//---------------------------------------------------------
	// 内部成员类
	//---------------------------------------------------------

	public enum UnderLine {
		
		NONE(0,0),
		
		COMMON(4,1),
		
		BOLD(21,2);

		private final String code;
		private final int len;

		UnderLine(int code,int len) {
			if(code == 0){
				this.code = "";
				this.len = 0;
			}else {
				this.code = code+";";
				this.len = len+1;
			}
		}

		private int getLen() {
			return len;
		}

		private String getCode() {
			return code;
		}
	}

	@SuppressWarnings("unused")
	public enum Color {
		
		NONE(0,0),
		
		BLACK(30,2),
		
		LIGHT_RED(31,2),
		
		RED(91,2),
		
		LIGHT_GREEN(32,2),
		
		GREEN(92,2),
		
		LIGHT_YELLOW(33,2),
		
		YELLOW(93,2),
		
		LIGHT_BLUE(34,2),
		
		BLUE(94,2),
		
		LIGHT_PINK(35,2),
		
		PINK(95,2),
		
		LIGHT_CYAN(36,2),
		
		CYAN(96,2),
		
		LIGHT_GREY(37,2),
		
		GREY(90,2),
		
		WHITE(97,2);

		private final String backgroundCode;
		private final String foregroundCode;
		private final int len;

		Color(int code, int len) {
			if(code == 0){
				this.backgroundCode = this.foregroundCode = "";
				this.len = 0;
			}else {
				this.foregroundCode = code + ";";
				this.backgroundCode = code + 10 + ";";
				this.len = len + 1;
			}
		}

		private String getBackgroundCode() {
			return backgroundCode;
		}

		private String getForegroundCode() {
			return foregroundCode;
		}

		private int getLen() {
			return len;
		}
	}
}
ConsoleUtils

日志打印工具 分为debug info error三种级别 可为不同级别打印不同格式日志 可以自定义打印格式和注册新的变量解析器支持新的变量 和设置打印后处理器 如进行日志保存操作

测试用例运行结果如下

测试用例如下

public class ConsoleTest {
	private void printlnTestInfo() {
		ConsoleUtils.printlnDebug("这是条%s信息","DEBUG");
		ConsoleUtils.printlnInfo("这是条%s信息","INFO");
		ConsoleUtils.printlnError("这是条%s信息","ERROR");
	}

	@Test
	public void testConsoleUtil(){
		ConsoleUtils.recordAccessThread();

		ConsoleUtils.printInfoLine("=","info等级");
		printlnTestInfo();
		ConsoleUtils.setLevel(Level.DEBUG);
		ConsoleUtils.printDebugLine("=","debug等级");
		printlnTestInfo();
		ConsoleUtils.setLevel(Level.ERROR);
		ConsoleUtils.printErrorLine("=","error等级");
		printlnTestInfo();

		ConsoleUtils.printErrorLine("=","error下划删除线字体",-12);
		Level.ERROR.getFont().setForeground(ConsoleFont.Color.LIGHT_YELLOW).setBold(true)
				.setItalic(true).save().setUnderLine(ConsoleFont.UnderLine.BOLD)
				.setDeleteLine(true);
		printlnTestInfo();
		Level.ERROR.getFont().load();
		String logFormat = Level.ERROR.getLogFormat();

		ConsoleUtils.printErrorLine("-",null);
		ConsoleUtils.printErrorLine(null,"日志格式");
		ConsoleUtils.printErrorLine("-",null);

		Level.ERROR.setLogFormat(null);
		ConsoleUtils.printlnError("logFormat: %s",logFormat);
		Level.ERROR.setLogFormat("error: ");
		printlnTestInfo();
		Level.ERROR.setLogFormat(null);
		System.setProperty("hello","你好");
		logFormat = "${extensionName}${space}${time:HH:mm:ss} ${windir} hello:${hello} ${randomInt}${space}";
		Level.ERROR.setLogFormat(logFormat);
		ConsoleUtils.registerParsers(groupParser -> {
			groupParser.registerVariableParser(params->new Random().nextInt()+"","randomInt")
					.registerVariableParser(params -> params.getFileName().substring(
									params.getFileName().lastIndexOf(".")+1),"extensionName");
		});

		ConsoleUtils.printErrorLine("=","自定义变量解析器和日志后处理器");
		ConsoleUtils.registerLogPostProcessor((level, prefix, log)->
				System.out.println("收到日志处理请求: "+prefix.concat(log)));
		printlnTestInfo();

		ConsoleUtils.printErrorLine("=","打印访问线程信息");
		ConsoleUtils.printlnRecordAccessThreadInfo();
	}
}

代码片段 可点击上面的gitee链接查看最新代码

package com.nailsoul.commons.lang;

import java.lang.ref.WeakReference;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Consumer;
import java.util.regex.Matcher;
import java.util.regex.Pattern;


@SuppressWarnings({"unused", "UnusedReturnValue"})
public class ConsoleUtils {
	private static Level level = Level.INFO;

	private static final String FILE_NAME = ConsoleUtils.class.getSimpleName().concat(".java");
	private static final String DEFAULT_LOG_FORMAT =
			"${levelName}${space}${threadName}${space}${simpleClassName}.${methodName}[${fileLine}]${space}${time:HH:mm:ss.sss}${space}";
	private static final LogFormatParser LOG_FORMAT_PARSER = new LogFormatParser();
	private static final List LOG_POST_PROCESSORS = new LinkedList<>();
	private static Set recordAccessThreadNames;
	static {
		registerLogPostProcessor((level,prefix,log)->
				System.out.print(level.getFont().handleMessage(prefix.concat(log))));
	}

	public static Set getRecordAccessThreadNames(){
		return recordAccessThreadNames;
	}

	public static ConsoleUtils printlnRecordAccessThreadInfo() {
		String preLog = parseLogPreInfo(Level.INFO);
		String msg = "总访问线程数:" + recordAccessThreadNames.size() +
				",访问线程列表:" + recordAccessThreadNames;
		System.out.println(level.getFont().handleMessage(preLog+msg));
		return null;
	}

	public static ConsoleUtils recordAccessThread(){
		if(recordAccessThreadNames == null){
			recordAccessThreadNames = new LinkedHashSet<>();
			registerLogPostProcessor((level,prefix,log)->
					recordAccessThreadNames.add(Thread.currentThread().getName()));
		}
		return null;
	}

	public static ConsoleUtils setLevel(Level level){
		Objects.requireNonNull(level);
		ConsoleUtils.level = level;
		return null;
	}

	public static ConsoleUtils registerParsers(Consumer consumer) {
		consumer.accept(LOG_FORMAT_PARSER.parserContext);
		return null;
	}

	public static ConsoleUtils registerLogPostProcessor(LogPostProcessor logPostProcessor){
		LOG_POST_PROCESSORS.add(logPostProcessor);
		return null;
	}

	public static ConsoleUtils printInfo(Object msg){
		if(level.isInfo()){
			print(Level.INFO,msg);
		}
		return null;
	}

	public static ConsoleUtils printlnInfo(Object msg){
		if(level.isInfo()){
			println(Level.INFO,msg, true);
		}
        return null;
    }

    public static ConsoleUtils printlnInfo(boolean condition, Object msg) {
        if(condition && level.isInfo()){
            printlnInfo(msg);
        }
        return null;
    }

	public static ConsoleUtils printlnInfo(String format, Object ... args){
		if(level.isInfo()){
			String str = String.format(format, args);
			printlnInfo(str);
		}
		return null;
	}

	public static ConsoleUtils printInfoLine(String symbol,String title) {
		printInfoLine(symbol,title,0);
		return null;
	}

	public static ConsoleUtils printInfoLine(String symbol,String title,int offset) {
		if(level.isInfo()){
			printLine0(Level.INFO,symbol,title,66+offset);
		}
		return null;
	}


	public static ConsoleUtils printDebug(Object msg){
		if(level.isDebug()){
			print(Level.DEBUG,msg);
		}
		return null;
	}

	public static ConsoleUtils printlnDebug(Object msg){
		if(level.isDebug()){
			println(Level.DEBUG,msg, true);
		}
		return null;
	}

	public static ConsoleUtils printlnDebug(boolean condition, Object msg) {
		if(condition && level.isDebug()){
			printlnDebug(msg);
		}
		return null;
	}

	public static ConsoleUtils printlnDebug(String format, Object ... args){
		if(level.isDebug()){
			String str = String.format(format, args);
			printlnDebug(str);
		}
		return null;
	}

	public static ConsoleUtils printDebugLine(String symbol,String title) {
		printDebugLine(symbol,title,0);
		return null;
	}

	public static ConsoleUtils printDebugLine(String symbol,String title,int offset) {
		if(level.isDebug()){
			printLine0(Level.DEBUG,symbol,title,66+offset);
		}
		return null;
	}


	public static ConsoleUtils printError(Object msg){
		if(level.isError()){
			print(Level.ERROR,msg);
		}
		return null;
	}

	public static ConsoleUtils printlnError(Object msg){
		if(level.isError()){
			println(Level.ERROR,msg, true);
		}
		return null;
	}

	public static ConsoleUtils printlnError(boolean condition, Object msg) {
		if(level.isError()){
			if(condition){
				printlnError(msg);
			}
		}
		return null;
	}

	public static ConsoleUtils printlnError(String format, Object ... args){
		if(level.isError()){
			String str = String.format(format, args);
			printlnError(str);
		}
		return null;
	}

	public static ConsoleUtils printErrorLine(String symbol, String title) {
		printErrorLine(symbol,title,0);
		return null;
	}

	public static ConsoleUtils printErrorLine(String symbol, String title, int offset) {
		if(level.isError()){
			printLine0(Level.ERROR,symbol,title,66+offset);
		}
		return null;
	}


	private static void print(Level level,Object msg) {
		doPostProcessor(level,"",msg.toString());
	}

	private static void doPostProcessor(Level level, String prefix, String log) {
		for (LogPostProcessor logPostProcessor : LOG_POST_PROCESSORS) {
			logPostProcessor.postProcess(level, prefix, log);
		}
	}

	private static void println(Level level, Object msg, boolean printPreLogInfo) {
		String log = msg.toString().concat("n");
		String prefix = printPreLogInfo ? parseLogPreInfo(level) : "";

		doPostProcessor(level,prefix,log);
	}

	private static void printLine0(Level level, String symbol, String title, int count) {
		if(symbol == null || symbol.length() == 0){
			symbol = "";
			count = 0;
		}
		if(title == null){
			println(level,nCopies(symbol,count), false);
		}else {
			String symbolPart = nCopies(symbol, count/2);
			int len = count + title.length();
			@SuppressWarnings("StringBufferReplaceableByString")
			String msg = new StringBuilder(len)
					.append(symbolPart)
					.append(title)
					.append(symbolPart)
					.toString();
			println(level,msg,false);
		}
	}

	private static String parseLogPreInfo(Level level){
		String logFormat = level.getLogFormat();
		if(logFormat == null){
			return "";
		}
		return ConsoleUtils.level.needParseLogFormat
				? LOG_FORMAT_PARSER.parseLogFormat(logFormat)
				: logFormat;
    }

	private static String nCopies(String str, int depth) {
		return String.join("", Collections.nCopies(depth,str));
	}

	public enum Level{
		
		DEBUG(0,ConsoleFont.generate().setForeground(ConsoleFont.Color.BLUE)),
		
		INFO(1,ConsoleFont.success()),
		
		ERROR(2,ConsoleFont.error());

		private final ConsoleFont font;
		private String logFormat = DEFAULT_LOG_FORMAT;
		private boolean needParseLogFormat = true;
		private final int permission;

		Level(int permission, ConsoleFont font) {
			this.font = font;
			this.permission = permission;
		}

		public boolean isInfo(){
			return permission <= INFO.permission;
		}

		public boolean isDebug(){
			return permission <= DEBUG.permission;
		}

		public boolean isError(){
			return permission <= ERROR.permission;
		}

		public ConsoleFont getFont() {
			return font;
		}

		public String getLogFormat() {
			return logFormat;
		}

		public void setLogFormat(String logFormat) {
			if(logFormat == null || logFormat.length() == 0){
				this.logFormat = "";
				needParseLogFormat = false;
			}else {
				this.logFormat = logFormat;
				needParseLogFormat = logFormat.matches(LogFormatParser.FORMAT_VARIABLE_GROUP_SEARCH);
			}

		}
	}

	//---------------------------------------------------------
	// logFormat处理
	//---------------------------------------------------------

	private static class LogFormatParser{
		private static final String FORMAT_VARIABLE_GROUP_SEARCH = "\$\{(.+?)}";
		private final VariableParserContext parserContext = new VariableParserContext();
		private final Pattern compile = Pattern.compile(FORMAT_VARIABLE_GROUP_SEARCH);

		public final String parseLogFormat(String logFormat){
			Objects.requireNonNull(logFormat);
			Matcher matcher = compile.matcher(logFormat);
			int capacity = logFormat.length() + logFormat.length() / 2;
			StringBuilder builder = new StringBuilder(capacity);
			int cursor = 0;
			int groupIndex = 1;
			while (matcher.find()){
				String variableName = matcher.group(groupIndex);
				VariableParseParams params = obtainVariableParams(variableName);
				String variableValue = parserContext.parse(params);

				// 把分组头前不是分组的据添加到builder中 -2是减${的长度
				int startByGroup = matcher.start(groupIndex)-2;
				if(cursor < startByGroup){
					builder.append(logFormat, cursor, startByGroup);
				}
				if(variableValue != null && variableValue.length() > 0){
					builder.append(variableValue);
				}

				// 跟新光标到分组的下一个字符
				cursor = matcher.end(groupIndex)+1;
			}
			if(cursor < logFormat.length()){
				// 不放过一个
				builder.append(logFormat,cursor,logFormat.length());
			}
			return builder.toString();
		}

		private VariableParseParams obtainVariableParams(String variableName) {
			String variableParam = null;
			int index = variableName.indexOf(":");
			if(index > 0){
				if(index == variableName.length() - 1){
					throw new RuntimeException("变量最后值不能是: "+"${"+variableName+"}");
				}
				variableParam = variableName.substring(index+1);
				variableName = variableName.substring(0,index);
			}

			VariableParseParams params = VariableParseParams.obtain();
			if(params.isBind()){
				params.bind(variableName,variableParam);
				return params;
			}

			StackTraceElement[] stackTraces = Thread.currentThread().getStackTrace();
			StackTraceElement stackTrace = null;
			for (int i = 2; i < stackTraces.length; i++) {
				if(FILE_NAME.equals(stackTraces[i].getFileName())){
					continue;
				}
				stackTrace = stackTraces[i];
				break;
			}
			if(stackTrace == null){
				stackTrace = stackTraces[stackTraces.length - 1];
			}

			params = VariableParseParams.obtain();
			params.bind(variableName,variableParam,stackTrace);
			return params;
		}
	}

	private static class VariableParserContext extends FormatVariableGroupParser{

		@Override
		protected Map generateParsers() {
			return new ConcurrentHashMap(16){
				private final FormatVariableParser defaultParser = new CoreVariableParser();
				@Override
				public FormatVariableParser get(Object key) {
					FormatVariableParser parser;
					return (parser = super.get(key)) == null ? defaultParser : parser;
				}
			};
		}

	}

	private static class CoreVariableParser extends FormatVariableGroupParser{

		@Override
		protected Map generateParsers() {
			return new ConcurrentHashMap(16){
				private final FormatVariableParser defaultParser = params->{
					//获取系统属性和环境变量
					String name = params.getName();
					String value = System.getProperty(name);
					if(value != null){
						return value;
					}
					return System.getenv(name);
				};
				@Override
				public FormatVariableParser get(Object key) {
					FormatVariableParser parser;
					return (parser = super.get(key)) == null ? defaultParser : parser;
				}
			};
		}

		@Override
		protected void init() {
			//"levelName","threadName","space","simpleClassName","methodName","fileLine","time";
			registerVariableParser(params ->
							level.name().length() < 5 ? level.name()+" " : level.name(),
					"levelName");
			registerVariableParser(VariableParseParams::getThreadName,
					"threadName");
			registerVariableParser(params->"    ","space");
			registerVariableParser(VariableParseParams::getSimpleClassName,
					"simpleClassName");
			registerVariableParser(VariableParseParams::getMethodName,
					"methodName");
			registerVariableParser(VariableParseParams::getFileName,
					"fileName");
			registerVariableParser(VariableParseParams::getFileLineStr,
					"fileLine");
			registerVariableParser(VariableParseParams::getClassName,
					"className");
			registerVariableParser(params->{
				String pattern = params.getParam("dd HH:mm:ss.sss");
				SimpleDateFormat sdf = new SimpleDateFormat(pattern);
				return sdf.format(new Date());
			},"time");
		}
	}

	public static abstract class FormatVariableGroupParser implements FormatVariableParser{
		//防止迭代时在添加或删除元素
		private final Map parsers = generateParsers();

		protected Map generateParsers() {
			return new ConcurrentHashMap<>(16);
		}

		public FormatVariableGroupParser(){
			init();
		}

		protected void init() {
		}

		@Override
		public String parse(VariableParseParams params) {
			FormatVariableParser parser = parsers.get(params.getName());
			return parser.parse(params);
		}

		public FormatVariableGroupParser registerVariableParser(
				FormatVariableParser parser,String ... variableNames){
			Objects.requireNonNull(parser);
			for (String variableName : variableNames) {
				parsers.put(variableName,parser);
			}
			return this;
		}

		public FormatVariableGroupParser registerVariableParser(
				FormatVariableParser parser,Iterable iterable){
			Objects.requireNonNull(parser);
			for (String variableName : iterable) {
				parsers.put(variableName,parser);
			}
			return this;
		}

		public FormatVariableGroupParser unregisterVariableParser(String ... variableNames){
			for (String variableName : variableNames) {
				parsers.remove(variableName);
			}
			for (FormatVariableParser parser : parsers.values()) {
				if(parser instanceof FormatVariableGroupParser){
					((FormatVariableGroupParser)parser).unregisterVariableParser(variableNames);
				}
			}
			return this;
		}

		public FormatVariableParser getVariableParser(String variableName){
			return parsers.get(variableName);
		}

		public Set getVariableNames(){
			return parsers.keySet();
		}
	}

	@FunctionalInterface
	public interface FormatVariableParser {
		
		String parse(VariableParseParams params);
	}

	@FunctionalInterface
	public interface LogPostProcessor{
		
		void postProcess(Level level,String prefix,String log);
	}

	public static class VariableParseParams {
		private static final ThreadLocal> THREAD_LOCAL =
				new ThreadLocal<>();

		private String name;
		private String param;
		private String className;
		private String simpleClassName;
		private String methodName;
		private String threadName;
		private String fileName;
		private int fileLine;
		private boolean bind;

		public boolean isBind() {
			return bind;
		}

		private void bind(String name, String param) {
			this.name = name;
			this.param = param;
			this.bind = true;
		}

		private void bind(String name, String param, StackTraceElement stackTrace) {
			bind(name, param);
			//noinspection ConstantConditions
			simpleClassName = stackTrace.getFileName().replace(".java","");
			this.className = stackTrace.getClassName();
			this.methodName = stackTrace.getMethodName();
			this.fileLine = stackTrace.getLineNumber();
			this.fileName = stackTrace.getFileName();
			this.threadName = Thread.currentThread().getName();
		}

		private static VariableParseParams obtain() {
			WeakReference paramsRef = THREAD_LOCAL.get();
			if(paramsRef == null || paramsRef.get() == null){
				paramsRef = new WeakReference<>(new VariableParseParams());
				THREAD_LOCAL.set(paramsRef);
			}
			return paramsRef.get();
		}

		public String getName() {
			return name;
		}

		public String getParam() {
			return param;
		}

		public String getParam(String defaultParam) {
			return param == null ? defaultParam : param;
		}

		public String getClassName() {
			return className;
		}

		public String getSimpleClassName() {
			return simpleClassName;
		}

		public String getMethodName() {
			return methodName;
		}

		public int getFileLine() {
			return fileLine;
		}

		public String getFileLineStr(){
			return String.valueOf(getFileLine());
		}

		public String getFileName() {
			return fileName;
		}

		public String getThreadName() {
			return threadName;
		}
	}
}
转载请注明:文章转载自 www.051e.com
本文地址:http://www.051e.com/it/984943.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 ©2023-2025 051e.com

ICP备案号:京ICP备12030808号