
让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;
}
}
}