前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >聊聊logback的ThrowableProxyConverter

聊聊logback的ThrowableProxyConverter

原创
作者头像
code4it
发布2023-12-03 21:01:29
2110
发布2023-12-03 21:01:29
举报
文章被收录于专栏:码匠的流水账码匠的流水账

本文主要研究一下logback的ThrowableProxyConverter

ThrowableHandlingConverter

ch/qos/logback/classic/pattern/ThrowableHandlingConverter.java

代码语言:javascript
复制
/**
 * Converter which handle throwables should be derived from this class.
 *
 */
public abstract class ThrowableHandlingConverter extends ClassicConverter {

    boolean handlesThrowable() {
        return true;
    }
}

ThrowableHandlingConverter继承了ClassicConverter,其handlesThrowable方法返回true

ThrowableProxyConverter

ch/qos/logback/classic/pattern/ThrowableProxyConverter.java

代码语言:javascript
复制
public class ThrowableProxyConverter extends ThrowableHandlingConverter {

    protected static final int BUILDER_CAPACITY = 2048;

    int lengthOption;
    List<EventEvaluator<ILoggingEvent>> evaluatorList = null;
    List<String> ignoredStackTraceLines = null;

    int errorCount = 0;

    @SuppressWarnings("unchecked")
    public void start() {

        String lengthStr = getFirstOption();

        if (lengthStr == null) {
            lengthOption = Integer.MAX_VALUE;
        } else {
            lengthStr = lengthStr.toLowerCase();
            if ("full".equals(lengthStr)) {
                lengthOption = Integer.MAX_VALUE;
            } else if ("short".equals(lengthStr)) {
                lengthOption = 1;
            } else {
                try {
                    lengthOption = Integer.parseInt(lengthStr);
                } catch (NumberFormatException nfe) {
                    addError("Could not parse [" + lengthStr + "] as an integer");
                    lengthOption = Integer.MAX_VALUE;
                }
            }
        }

        final List<String> optionList = getOptionList();

        if (optionList != null && optionList.size() > 1) {
            final int optionListSize = optionList.size();
            for (int i = 1; i < optionListSize; i++) {
                String evaluatorOrIgnoredStackTraceLine = (String) optionList.get(i);
                Context context = getContext();
                Map<String, EventEvaluator<?>> evaluatorMap = (Map<String, EventEvaluator<?>>) context.getObject(CoreConstants.EVALUATOR_MAP);
                EventEvaluator<ILoggingEvent> ee = (EventEvaluator<ILoggingEvent>) evaluatorMap.get(evaluatorOrIgnoredStackTraceLine);
                if (ee != null) {
                    addEvaluator(ee);
                } else {
                    addIgnoreStackTraceLine(evaluatorOrIgnoredStackTraceLine);
                }
            }
        }
        super.start();
    }

    //......
}    

ThrowableProxyConverter继承了ThrowableHandlingConverter,其start方法会先读取getFirstOption,该参数为lengthOption,为null则取Integer.MAX_VALUE,若为full则取Integer.MAX_VALUE,为short取1,其他的则解析该值,出现异常则取Integer.MAX_VALUE;之后取optionList的其他值,先通过evaluatorMap来取,若EventEvaluator不为null则执行addEvaluator,否则执行addIgnoreStackTraceLine

addEvaluator

代码语言:javascript
复制
    private void addEvaluator(EventEvaluator<ILoggingEvent> ee) {
        if (evaluatorList == null) {
            evaluatorList = new ArrayList<EventEvaluator<ILoggingEvent>>();
        }
        evaluatorList.add(ee);
    }

addEvaluator则是添加到evaluatorList

addIgnoreStackTraceLine

代码语言:javascript
复制
    private void addIgnoreStackTraceLine(String ignoredStackTraceLine) {
        if (ignoredStackTraceLines == null) {
            ignoredStackTraceLines = new ArrayList<String>();
        }
        ignoredStackTraceLines.add(ignoredStackTraceLine);
    }

addIgnoreStackTraceLine则是添加到ignoredStackTraceLines

convert

代码语言:javascript
复制
    public String convert(ILoggingEvent event) {

        IThrowableProxy tp = event.getThrowableProxy();
        if (tp == null) {
            return CoreConstants.EMPTY_STRING;
        }

        // an evaluator match will cause stack printing to be skipped
        if (evaluatorList != null) {
            boolean printStack = true;
            for (int i = 0; i < evaluatorList.size(); i++) {
                EventEvaluator<ILoggingEvent> ee = evaluatorList.get(i);
                try {
                    if (ee.evaluate(event)) {
                        printStack = false;
                        break;
                    }
                } catch (EvaluationException eex) {
                    errorCount++;
                    if (errorCount < CoreConstants.MAX_ERROR_COUNT) {
                        addError("Exception thrown for evaluator named [" + ee.getName() + "]", eex);
                    } else if (errorCount == CoreConstants.MAX_ERROR_COUNT) {
                        ErrorStatus errorStatus = new ErrorStatus("Exception thrown for evaluator named [" + ee.getName() + "].", this, eex);
                        errorStatus.add(new ErrorStatus("This was the last warning about this evaluator's errors."
                                        + "We don't want the StatusManager to get flooded.", this));
                        addStatus(errorStatus);
                    }
                }
            }

            if (!printStack) {
                return CoreConstants.EMPTY_STRING;
            }
        }

        return throwableProxyToString(tp);
    }

convert方法先从event获取IThrowableProxy,若为null则返回空字符串;之后判断evaluatorList是否为null,不为null则遍历挨个执行evaluate(event),若为true则printStack设置为false,跳出循环,当printStack为false时,返回空字符串,否则通过throwableProxyToString转为字符串返回

throwableProxyToString

代码语言:javascript
复制
    protected String throwableProxyToString(IThrowableProxy tp) {
        StringBuilder sb = new StringBuilder(BUILDER_CAPACITY);

        recursiveAppend(sb, null, ThrowableProxyUtil.REGULAR_EXCEPTION_INDENT, tp);

        return sb.toString();
    }

    private void recursiveAppend(StringBuilder sb, String prefix, int indent, IThrowableProxy tp) {
        if (tp == null)
            return;
        subjoinFirstLine(sb, prefix, indent, tp);
        sb.append(CoreConstants.LINE_SEPARATOR);
        subjoinSTEPArray(sb, indent, tp);
        IThrowableProxy[] suppressed = tp.getSuppressed();
        if (suppressed != null) {
            for (IThrowableProxy current : suppressed) {
                recursiveAppend(sb, CoreConstants.SUPPRESSED, indent + ThrowableProxyUtil.SUPPRESSED_EXCEPTION_INDENT, current);
            }
        }
        recursiveAppend(sb, CoreConstants.CAUSED_BY, indent, tp.getCause());
    }

throwableProxyToString主要是递归执行recursiveAppend,它先执行subjoinFirstLine、再执行subjoinSTEPArray、最后继续递归

subjoinSTEPArray

代码语言:javascript
复制
    protected void subjoinSTEPArray(StringBuilder buf, int indent, IThrowableProxy tp) {
        StackTraceElementProxy[] stepArray = tp.getStackTraceElementProxyArray();
        int commonFrames = tp.getCommonFrames();

        boolean unrestrictedPrinting = lengthOption > stepArray.length;

        int maxIndex = (unrestrictedPrinting) ? stepArray.length : lengthOption;
        if (commonFrames > 0 && unrestrictedPrinting) {
            maxIndex -= commonFrames;
        }

        int ignoredCount = 0;
        for (int i = 0; i < maxIndex; i++) {
            StackTraceElementProxy element = stepArray[i];
            if (!isIgnoredStackTraceLine(element.toString())) {
                ThrowableProxyUtil.indent(buf, indent);
                printStackLine(buf, ignoredCount, element);
                ignoredCount = 0;
                buf.append(CoreConstants.LINE_SEPARATOR);
            } else {
                ++ignoredCount;
                if (maxIndex < stepArray.length) {
                    ++maxIndex;
                }
            }
        }
        if (ignoredCount > 0) {
            printIgnoredCount(buf, ignoredCount);
            buf.append(CoreConstants.LINE_SEPARATOR);
        }

        if (commonFrames > 0 && unrestrictedPrinting) {
            ThrowableProxyUtil.indent(buf, indent);
            buf.append("... ").append(tp.getCommonFrames()).append(" common frames omitted").append(CoreConstants.LINE_SEPARATOR);
        }
    }

subjoinSTEPArray遍历StackTraceElementProxy数组,然后挨个判断isIgnoredStackTraceLine,若为false才执行printStackLine

isIgnoredStackTraceLine

代码语言:javascript
复制
    private boolean isIgnoredStackTraceLine(String line) {
        if (ignoredStackTraceLines != null) {
            for (String ignoredStackTraceLine : ignoredStackTraceLines) {
                if (line.contains(ignoredStackTraceLine)) {
                    return true;
                }
            }
        }
        return false;
    }

isIgnoredStackTraceLine主要是判断指定line是否包含了ignoredStackTraceLines,包含其中一个即返回true

小结

logback的ThrowableProxyConverter继承了ThrowableHandlingConverter,它定义了evaluatorList、ignoredStackTraceLines属性,它将继承自DynamicConverter的optionList做了划分,第一个option为打印异常堆栈的数,之后的option优先作为evaluatorList,若解析为evaluator为null则作为ignoredStackTraceLines参数。evaluatorList用于evaluate(event),若有个返回true则返回空字符串,而ignoredStackTraceLines则用于过滤包含这些的异常堆栈。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • ThrowableHandlingConverter
  • ThrowableProxyConverter
    • addEvaluator
      • addIgnoreStackTraceLine
      • convert
        • throwableProxyToString
          • subjoinSTEPArray
            • isIgnoredStackTraceLine
            • 小结
            领券
            问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档