系统日志logback
程序员文章站
2022-06-14 20:57:38
...
引用
logback-classic-1.0.3.jar
引用
logback-core-1.0.3.jar
引用
logstash-logback-encoder-1.2.jar
<?xml version="1.0" encoding="UTF-8"?> <configuration scan="true"> <!-- 将Maven pom.xml的属性应用到logback中来, 需要在pom.xml中指定build resources --> <property scope="system" name="APP_NAME" value="lifeix-payment" /> <property scope="system" name="APP_VERSION" value="1.0.0-Beta1" /> <property scope="system" name="APP_ENV" value="development" /> <property scope="system" name="LOG_DIR" value="/usr/local/tomcat/logs" /> <property scope="system" name="LOG_ORDER_DIR" value="/usr/local/tomcat/logs/task" /> <property scope="system" name="LOG_ORDER_NAME" value="lifeix-payment-order" /> <!-- 任务输出日志 --> <appender name="ordertask" class="ch.qos.logback.core.rolling.RollingFileAppender" > <filter class="ch.qos.logback.classic.filter.ThresholdFilter"> <level>debug</level> </filter> <file>${LOG_ORDER_DIR}/${LOG_ORDER_NAME}.log</file> <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> <!-- 日志每天进行rotate --> <fileNamePattern>${LOG_ORDER_DIR}/${LOG_ORDER_NAME}-%d{yyyy-MM-dd}.%i.log</fileNamePattern> <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP"> <!-- 每个日志文件大小不超过2GB --> <maxFileSize>2000MB</maxFileSize> </timeBasedFileNamingAndTriggeringPolicy> </rollingPolicy> <!-- 日志输出格式 --> <encoder> <pattern>%-20(%d{yyy-MM-dd HH:mm:ss.SSS} [%thread]) %-5level %logger{80} - %msg%n</pattern> </encoder> </appender> <appender name="ROLLING" class="ch.qos.logback.core.rolling.RollingFileAppender"> <filter class="ch.qos.logback.classic.filter.ThresholdFilter"> <level>info</level> </filter> <file>${LOG_DIR}/${APP_NAME}.log</file> <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> <!-- rollover daily --> <fileNamePattern>${LOG_DIR}/${APP_NAME}-%d{yyyy-MM-dd}.%i.log</fileNamePattern> <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP"> <!-- or whenever the file size reaches 2GB --> <maxFileSize>2000MB</maxFileSize> </timeBasedFileNamingAndTriggeringPolicy> </rollingPolicy> <encoder> <pattern>%-20(%d{yyy-MM-dd HH:mm:ss.SSS} [%thread]) %-5level %logger{80} - %msg%n</pattern> </encoder> </appender> <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender"> <filter class="ch.qos.logback.classic.filter.ThresholdFilter"> <level>info</level> </filter> <encoder> <pattern>%-20(%d{yyy-MM-dd HH:mm:ss.SSS} [%thread]) %-5level %logger{80} - %msg%n</pattern> </encoder> </appender> <!-- logstash appender settings --> <appender name="logstash" class="ch.qos.logback.core.rolling.RollingFileAppender"> <file>${LOG_DIR}/logstash_${APP_NAME}_logback.json</file> <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> <!-- rollover daily --> <fileNamePattern>${LOG_DIR}/logstash_${APP_NAME}_logback%d{yyyy-MM-dd}.%i.json</fileNamePattern> <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP"> <!-- or whenever the file size reaches 2MB --> <maxFileSize>2000MB</maxFileSize> </timeBasedFileNamingAndTriggeringPolicy> </rollingPolicy> <encoding>UTF-8</encoding> <encoder class="net.logstash.logback.encoder.LogstashEncoder" /> </appender> <root level="INFO"> <appender-ref ref="ROLLING" /> <appender-ref ref="CONSOLE" /> <appender-ref ref="logstash" /> </root> <!-- 对于一些特定的包进行默认日志级别设定 --> <logger name="org.kaleidofoundry.core" level="WARN" /> <logger name="net.rubyeye.xmemcached" level="INFO" /> <logger name="com.google.code.yanf4j.core" level="ERROR" /> <logger name="org.apache.mina.filter.logging" level="WARN" /> <logger name="com.lifeix.pay.api.util.PaymentOrderLog" level="DEBUG" additivity="false"> <appender-ref ref="ordertask" /> </logger> </configuration>
* Logback: the reliable, generic, fast and flexible logging framework. package ch.qos.logback.core.rolling; import java.io.File; import java.io.IOException; import static ch.qos.logback.core.CoreConstants.CODES_URL; import ch.qos.logback.core.FileAppender; import ch.qos.logback.core.rolling.helper.CompressionMode; /** * <code>RollingFileAppender</code> extends {@link FileAppender} to backup the * log files depending on {@link RollingPolicy} and {@link TriggeringPolicy}. * <p> * * For more information about this appender, please refer to the online manual * at http://logback.qos.ch/manual/appenders.html#RollingFileAppender * * @author Heinz Richter * @author Ceki Gülcü */ public class RollingFileAppender<E> extends FileAppender<E> { File currentlyActiveFile; TriggeringPolicy<E> triggeringPolicy; RollingPolicy rollingPolicy; public void start() { if (triggeringPolicy == null) { addWarn("No TriggeringPolicy was set for the RollingFileAppender named " + getName()); addWarn("For more information, please visit "+CODES_URL+"#rfa_no_tp"); return; } // we don't want to void existing log files if (!append) { addWarn("Append mode is mandatory for RollingFileAppender"); append = true; } if (rollingPolicy == null) { addError("No RollingPolicy was set for the RollingFileAppender named " + getName()); addError("For more information, please visit "+CODES_URL+"rfa_no_rp"); return; } if (isPrudent()) { if (rawFileProperty() != null) { addWarn("Setting \"File\" property to null on account of prudent mode"); setFile(null); } if (rollingPolicy.getCompressionMode() != CompressionMode.NONE) { addError("Compression is not supported in prudent mode. Aborting"); return; } } currentlyActiveFile = new File(getFile()); addInfo("Active log file name: " + getFile()); super.start(); } @Override public void stop() { if(rollingPolicy != null) rollingPolicy.stop(); if(triggeringPolicy != null) triggeringPolicy.stop(); super.stop(); } @Override public void setFile(String file) { // http://jira.qos.ch/browse/LBCORE-94 // allow setting the file name to null if mandated by prudent mode if (file != null && ((triggeringPolicy != null) || (rollingPolicy != null))) { addError("File property must be set before any triggeringPolicy or rollingPolicy properties"); addError("Visit "+CODES_URL+"#rfa_file_after for more information"); } super.setFile(file); } @Override public String getFile() { return rollingPolicy.getActiveFileName(); } /** * Implemented by delegating most of the rollover work to a rolling policy. */ public void rollover() { synchronized (lock) { // Note: This method needs to be synchronized because it needs exclusive // access while it closes and then re-opens the target file. // // make sure to close the hereto active log file! Renaming under windows // does not work for open files. this.closeOutputStream(); try { rollingPolicy.rollover(); } catch (RolloverFailure rf) { addWarn("RolloverFailure occurred. Deferring roll-over."); // we failed to roll-over, let us not truncate and risk data loss this.append = true; } try { // update the currentlyActiveFile // http://jira.qos.ch/browse/LBCORE-90 currentlyActiveFile = new File(rollingPolicy.getActiveFileName()); // This will also close the file. This is OK since multiple // close operations are safe. this.openFile(rollingPolicy.getActiveFileName()); } catch (IOException e) { addError("setFile(" + fileName + ", false) call failed.", e); } } } /** * This method differentiates RollingFileAppender from its super class. */ @Override protected void subAppend(E event) { // The roll-over check must precede actual writing. This is the // only correct behavior for time driven triggers. // We need to synchronize on triggeringPolicy so that only one rollover // occurs at a time synchronized (triggeringPolicy) { if (triggeringPolicy.isTriggeringEvent(currentlyActiveFile, event)) { rollover(); } } super.subAppend(event); } public RollingPolicy getRollingPolicy() { return rollingPolicy; } public TriggeringPolicy<E> getTriggeringPolicy() { return triggeringPolicy; } /** * Sets the rolling policy. In case the 'policy' argument also implements * {@link TriggeringPolicy}, then the triggering policy for this appender is * automatically set to be the policy argument. * * @param policy */ @SuppressWarnings("unchecked") public void setRollingPolicy(RollingPolicy policy) { rollingPolicy = policy; if (rollingPolicy instanceof TriggeringPolicy) { triggeringPolicy = (TriggeringPolicy<E>) policy; } } public void setTriggeringPolicy(TriggeringPolicy<E> policy) { triggeringPolicy = policy; if (policy instanceof RollingPolicy) { rollingPolicy = (RollingPolicy) policy; } } }
/** * Logback: the reliable, generic, fast and flexible logging framework. * Copyright (C) 1999-2011, QOS.ch. All rights reserved. * * This program and the accompanying materials are dual-licensed under * either the terms of the Eclipse Public License v1.0 as published by * the Eclipse Foundation * * or (per the licensee's choosing) * * under the terms of the GNU Lesser General Public License version 2.1 * as published by the Free Software Foundation. */ package ch.qos.logback.core.rolling; import java.io.File; import java.util.Date; import java.util.concurrent.Future; import ch.qos.logback.core.CoreConstants; import ch.qos.logback.core.rolling.helper.*; /** * <code>TimeBasedRollingPolicy</code> is both easy to configure and quite * powerful. It allows the roll over to be made based on time. It is possible to * specify that the roll over occur once per day, per week or per month. * * <p>For more information, please refer to the online manual at * http://logback.qos.ch/manual/appenders.html#TimeBasedRollingPolicy * * @author Ceki Gülcü */ public class TimeBasedRollingPolicy<E> extends RollingPolicyBase implements TriggeringPolicy<E> { static final String FNP_NOT_SET = "The FileNamePattern option must be set before using TimeBasedRollingPolicy. "; static final int INFINITE_HISTORY = 0; // WCS: without compression suffix FileNamePattern fileNamePatternWCS; private Compressor compressor; private RenameUtil renameUtil = new RenameUtil(); Future<?> future; private int maxHistory = INFINITE_HISTORY; private ArchiveRemover archiveRemover; TimeBasedFileNamingAndTriggeringPolicy<E> timeBasedFileNamingAndTriggeringPolicy; boolean cleanHistoryOnStart = false; public void start() { // set the LR for our utility object renameUtil.setContext(this.context); // find out period from the filename pattern if (fileNamePatternStr != null) { fileNamePattern = new FileNamePattern(fileNamePatternStr, this.context); determineCompressionMode(); } else { addWarn(FNP_NOT_SET); addWarn(CoreConstants.SEE_FNP_NOT_SET); throw new IllegalStateException(FNP_NOT_SET + CoreConstants.SEE_FNP_NOT_SET); } compressor = new Compressor(compressionMode); compressor.setContext(context); // wcs : without compression suffix fileNamePatternWCS = new FileNamePattern(Compressor.computeFileNameStr_WCS( fileNamePatternStr, compressionMode), this.context); addInfo("Will use the pattern " + fileNamePatternWCS + " for the active file"); if(compressionMode == CompressionMode.ZIP) { String zipEntryFileNamePatternStr = transformFileNamePattern2ZipEntry(fileNamePatternStr); zipEntryFileNamePattern = new FileNamePattern(zipEntryFileNamePatternStr, context); } if (timeBasedFileNamingAndTriggeringPolicy == null) { timeBasedFileNamingAndTriggeringPolicy = new DefaultTimeBasedFileNamingAndTriggeringPolicy<E>(); } timeBasedFileNamingAndTriggeringPolicy.setContext(context); timeBasedFileNamingAndTriggeringPolicy.setTimeBasedRollingPolicy(this); timeBasedFileNamingAndTriggeringPolicy.start(); // the maxHistory property is given to TimeBasedRollingPolicy instead of to // the TimeBasedFileNamingAndTriggeringPolicy. This makes it more convenient // for the user at the cost of inconsistency here. if (maxHistory != INFINITE_HISTORY) { archiveRemover = timeBasedFileNamingAndTriggeringPolicy.getArchiveRemover(); archiveRemover.setMaxHistory(maxHistory); if(cleanHistoryOnStart) { addInfo("Cleaning on start up"); archiveRemover.clean(new Date(timeBasedFileNamingAndTriggeringPolicy.getCurrentTime())); } } super.start(); } private String transformFileNamePattern2ZipEntry(String fileNamePatternStr) { String slashified = FileFilterUtil.slashify(fileNamePatternStr); return FileFilterUtil.afterLastSlash(slashified); } public void setTimeBasedFileNamingAndTriggeringPolicy( TimeBasedFileNamingAndTriggeringPolicy<E> timeBasedTriggering) { this.timeBasedFileNamingAndTriggeringPolicy = timeBasedTriggering; } public TimeBasedFileNamingAndTriggeringPolicy<E> getTimeBasedFileNamingAndTriggeringPolicy() { return timeBasedFileNamingAndTriggeringPolicy; } public void rollover() throws RolloverFailure { // when rollover is called the elapsed period's file has // been already closed. This is a working assumption of this method. String elapsedPeriodsFileName = timeBasedFileNamingAndTriggeringPolicy .getElapsedPeriodsFileName(); String elpasedPeriodStem = FileFilterUtil.afterLastSlash(elapsedPeriodsFileName); if (compressionMode == CompressionMode.NONE) { if (getParentsRawFileProperty() != null) { renameUtil.rename(getParentsRawFileProperty(), elapsedPeriodsFileName); } // else { nothing to do if CompressionMode == NONE and parentsRawFileProperty == null } } else { if (getParentsRawFileProperty() == null) { future = asyncCompress(elapsedPeriodsFileName, elapsedPeriodsFileName, elpasedPeriodStem); } else { future = renamedRawAndAsyncCompress(elapsedPeriodsFileName, elpasedPeriodStem); } } if (archiveRemover != null) { archiveRemover.clean(new Date(timeBasedFileNamingAndTriggeringPolicy.getCurrentTime())); } } Future asyncCompress(String nameOfFile2Compress, String nameOfCompressedFile, String innerEntryName) throws RolloverFailure { AsynchronousCompressor ac = new AsynchronousCompressor(compressor); return ac.compressAsynchronously(nameOfFile2Compress, nameOfCompressedFile, innerEntryName); } Future renamedRawAndAsyncCompress(String nameOfCompressedFile, String innerEntryName) throws RolloverFailure { String parentsRawFile = getParentsRawFileProperty(); String tmpTarget = parentsRawFile + System.nanoTime() + ".tmp"; renameUtil.rename(parentsRawFile, tmpTarget); return asyncCompress(tmpTarget, nameOfCompressedFile, innerEntryName); } /** * * The active log file is determined by the value of the parent's filename * option. However, in case the file name is left blank, then, the active log * file equals the file name for the current period as computed by the * <b>FileNamePattern</b> option. * * <p>The RollingPolicy must know whether it is responsible for changing the * name of the active file or not. If the active file name is set by the user * via the configuration file, then the RollingPolicy must let it like it is. * If the user does not specify an active file name, then the RollingPolicy * generates one. * * <p> To be sure that the file name used by the parent class has been * generated by the RollingPolicy and not specified by the user, we keep track * of the last generated name object and compare its reference to the parent * file name. If they match, then the RollingPolicy knows it's responsible for * the change of the file name. * */ public String getActiveFileName() { String parentsRawFileProperty = getParentsRawFileProperty(); if (parentsRawFileProperty != null) { return parentsRawFileProperty; } else { return timeBasedFileNamingAndTriggeringPolicy .getCurrentPeriodsFileNameWithoutCompressionSuffix(); } } public boolean isTriggeringEvent(File activeFile, final E event) { return timeBasedFileNamingAndTriggeringPolicy.isTriggeringEvent(activeFile, event); } /** * Get the number of archive files to keep. * * @return number of archive files to keep */ public int getMaxHistory() { return maxHistory; } /** * Set the maximum number of archive files to keep. * * @param maxHistory * number of archive files to keep */ public void setMaxHistory(int maxHistory) { this.maxHistory = maxHistory; } public boolean isCleanHistoryOnStart() { return cleanHistoryOnStart; } /** * Should archive removal be attempted on application start up? Default is false. * @since 1.0.1 * @param cleanHistoryOnStart */ public void setCleanHistoryOnStart(boolean cleanHistoryOnStart) { this.cleanHistoryOnStart = cleanHistoryOnStart; } @Override public String toString() { return "c.q.l.core.rolling.TimeBasedRollingPolicy"; } }
/** * Logback: the reliable, generic, fast and flexible logging framework. * Copyright (C) 1999-2011, QOS.ch. All rights reserved. * * This program and the accompanying materials are dual-licensed under * either the terms of the Eclipse Public License v1.0 as published by * the Eclipse Foundation * * or (per the licensee's choosing) * * under the terms of the GNU Lesser General Public License version 2.1 * as published by the Free Software Foundation. */ package ch.qos.logback.core.rolling; import java.io.File; import java.util.Date; import ch.qos.logback.core.joran.spi.NoAutoStart; import ch.qos.logback.core.rolling.helper.CompressionMode; import ch.qos.logback.core.rolling.helper.FileFilterUtil; import ch.qos.logback.core.rolling.helper.SizeAndTimeBasedArchiveRemover; import ch.qos.logback.core.util.FileSize; @NoAutoStart public class SizeAndTimeBasedFNATP<E> extends TimeBasedFileNamingAndTriggeringPolicyBase<E> { int currentPeriodsCounter = 0; FileSize maxFileSize; String maxFileSizeAsString; @Override public void start() { // we depend on certain fields having been initialized // in super.start() super.start(); archiveRemover = new SizeAndTimeBasedArchiveRemover(tbrp.fileNamePattern, rc); archiveRemover.setContext(context); // we need to get the correct value of currentPeriodsCounter. // usually the value is 0, unless the appender or the application // is stopped and restarted within the same period String regex = tbrp.fileNamePattern.toRegex(dateInCurrentPeriod); String stemRegex = FileFilterUtil.afterLastSlash(regex); computeCurrentPeriodsHighestCounterValue(stemRegex); started = true; } void computeCurrentPeriodsHighestCounterValue(final String stemRegex) { File file = new File(getCurrentPeriodsFileNameWithoutCompressionSuffix()); File parentDir = file.getParentFile(); File[] matchingFileArray = FileFilterUtil .filesInFolderMatchingStemRegex(parentDir, stemRegex); if (matchingFileArray == null || matchingFileArray.length == 0) { currentPeriodsCounter = 0; return; } currentPeriodsCounter = FileFilterUtil.findHighestCounter(matchingFileArray, stemRegex); // if parent raw file property is not null, then the next // counter is max found counter+1 if (tbrp.getParentsRawFileProperty() != null || (tbrp.compressionMode != CompressionMode.NONE)) { // TODO test me currentPeriodsCounter++; } } // IMPORTANT: This field can be updated by multiple threads. It follows that // its values may *not* be incremented sequentially. However, we don't care // about the actual value of the field except that from time to time the // expression (invocationCounter++ & invocationMask) == invocationMask) should be true. private int invocationCounter; private int invocationMask = 0x1; public boolean isTriggeringEvent(File activeFile, final E event) { long time = getCurrentTime(); if (time >= nextCheck) { Date dateInElapsedPeriod = dateInCurrentPeriod; elapsedPeriodsFileName = tbrp.fileNamePatternWCS .convertMultipleArguments(dateInElapsedPeriod, currentPeriodsCounter); currentPeriodsCounter = 0; setDateInCurrentPeriod(time); computeNextCheck(); return true; } // for performance reasons, check for changes every 16,invocationMask invocations if (((++invocationCounter) & invocationMask) != invocationMask) { return false; } if (invocationMask < 0x0F) { invocationMask = (invocationMask << 1) + 1; } if (activeFile.length() >= maxFileSize.getSize()) { elapsedPeriodsFileName = tbrp.fileNamePatternWCS .convertMultipleArguments(dateInCurrentPeriod, currentPeriodsCounter); currentPeriodsCounter++; return true; } return false; } private String getFileNameIncludingCompressionSuffix(Date date, int counter) { return tbrp.fileNamePattern.convertMultipleArguments( dateInCurrentPeriod, counter); } @Override public String getCurrentPeriodsFileNameWithoutCompressionSuffix() { return tbrp.fileNamePatternWCS.convertMultipleArguments( dateInCurrentPeriod, currentPeriodsCounter); } public String getMaxFileSize() { return maxFileSizeAsString; } public void setMaxFileSize(String maxFileSize) { this.maxFileSizeAsString = maxFileSize; this.maxFileSize = FileSize.valueOf(maxFileSize); } }
* Logback: the reliable, generic, fast and flexible logging framework. package ch.qos.logback.classic.filter; import ch.qos.logback.classic.Level; import ch.qos.logback.classic.spi.ILoggingEvent; import ch.qos.logback.core.filter.Filter; import ch.qos.logback.core.spi.FilterReply; /** * Filters events below the threshold level. * * Events with a level below the specified * level will be denied, while events with a level * equal or above the specified level will trigger a * FilterReply.NEUTRAL result, to allow the rest of the * filter chain process the event. * * For more information about filters, please refer to the online manual at * http://logback.qos.ch/manual/filters.html#thresholdFilter * * @author Sébastien Pennec */ public class ThresholdFilter extends Filter<ILoggingEvent> { Level level; @Override public FilterReply decide(ILoggingEvent event) { if (!isStarted()) { return FilterReply.NEUTRAL; } if (event.getLevel().isGreaterOrEqual(level)) { return FilterReply.NEUTRAL; } else { return FilterReply.DENY; } } public void setLevel(String level) { this.level = Level.toLevel(level); } public void start() { if (this.level != null) { super.start(); } } }
/** * Logback: the reliable, generic, fast and flexible logging framework. * Copyright (C) 1999-2011, QOS.ch. All rights reserved. * * This program and the accompanying materials are dual-licensed under * either the terms of the Eclipse Public License v1.0 as published by * the Eclipse Foundation * * or (per the licensee's choosing) * * under the terms of the GNU Lesser General Public License version 2.1 * as published by the Free Software Foundation. */ package ch.qos.logback.core; import java.util.Arrays; import ch.qos.logback.core.joran.spi.ConsoleTarget; import ch.qos.logback.core.status.Status; import ch.qos.logback.core.status.WarnStatus; /** * ConsoleAppender appends log events to <code>System.out</code> or * <code>System.err</code> using a layout specified by the user. The default * target is <code>System.out</code>. * * For more information about this appender, please refer to the online manual * at http://logback.qos.ch/manual/appenders.html#ConsoleAppender * * @author Ceki Gülcü * @author Tom SH Liu * @author Ruediger Dohna */ public class ConsoleAppender<E> extends OutputStreamAppender<E> { protected ConsoleTarget target = ConsoleTarget.SystemOut; /** * Sets the value of the <b>Target</b> option. Recognized values are * "System.out" and "System.err". Any other value will be ignored. */ public void setTarget(String value) { ConsoleTarget t = ConsoleTarget.findByName(value.trim()); if (t == null) { targetWarn(value); } else { target = t; } } /** * Returns the current value of the <b>target</b> property. The default value * of the option is "System.out". * * See also {@link #setTarget}. */ public String getTarget() { return target.getName(); } private void targetWarn(String val) { Status status = new WarnStatus("[" + val + "] should be one of " + Arrays.toString(ConsoleTarget.values()), this); status.add(new WarnStatus( "Using previously set target, System.out by default.", this)); addStatus(status); } @Override public void start() { setOutputStream(target.getStream()); super.start(); } }
* Licensed under the Apache License, Version 2.0 (the "License"); package net.logstash.logback.encoder; import static org.apache.commons.io.IOUtils.*; import java.io.IOException; import java.util.Map; import java.util.Map.Entry; import org.apache.commons.lang.time.FastDateFormat; import ch.qos.logback.classic.spi.ILoggingEvent; import ch.qos.logback.classic.spi.IThrowableProxy; import ch.qos.logback.classic.spi.ThrowableProxyUtil; import ch.qos.logback.core.Context; import ch.qos.logback.core.CoreConstants; import ch.qos.logback.core.encoder.EncoderBase; import com.fasterxml.jackson.core.JsonGenerator.Feature; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.node.ObjectNode; public class LogstashEncoder extends EncoderBase<ILoggingEvent> { private static final ObjectMapper MAPPER = new ObjectMapper().configure(Feature.ESCAPE_NON_ASCII, true); private static final FastDateFormat ISO_DATETIME_TIME_ZONE_FORMAT_WITH_MILLIS = FastDateFormat.getInstance("yyyy-MM-dd'T'HH:mm:ss.SSSZZ"); private static final StackTraceElement DEFAULT_CALLER_DATA = new StackTraceElement("", "", "", 0); private boolean immediateFlush = true; @Override public void doEncode(ILoggingEvent event) throws IOException { ObjectNode eventNode = MAPPER.createObjectNode(); eventNode.put("@timestamp", ISO_DATETIME_TIME_ZONE_FORMAT_WITH_MILLIS.format(event.getTimeStamp())); eventNode.put("@message", event.getFormattedMessage()); eventNode.put("@fields", createFields(event)); write(MAPPER.writeValueAsBytes(eventNode), outputStream); write(CoreConstants.LINE_SEPARATOR, outputStream); if (immediateFlush) { outputStream.flush(); } } private ObjectNode createFields(ILoggingEvent event) { ObjectNode fieldsNode = MAPPER.createObjectNode(); fieldsNode.put("logger_name", event.getLoggerName()); fieldsNode.put("thread_name", event.getThreadName()); fieldsNode.put("level", event.getLevel().toString()); fieldsNode.put("level_value", event.getLevel().toInt()); StackTraceElement callerData = extractCallerData(event); fieldsNode.put("caller_class_name", callerData.getClassName()); fieldsNode.put("caller_method_name", callerData.getMethodName()); fieldsNode.put("caller_file_name", callerData.getFileName()); fieldsNode.put("caller_line_number", callerData.getLineNumber()); IThrowableProxy throwableProxy = event.getThrowableProxy(); if (throwableProxy != null) { fieldsNode.put("stack_trace", ThrowableProxyUtil.asString(throwableProxy)); } Context context = getContext(); if (context != null) { addPropertiesAsFields(fieldsNode, context.getCopyOfPropertyMap()); } addPropertiesAsFields(fieldsNode, event.getMDCPropertyMap()); return fieldsNode; } private void addPropertiesAsFields(final ObjectNode fieldsNode, final Map<String, String> properties) { if (properties != null) { for (Entry<String, String> entry : properties.entrySet()) { String key = entry.getKey(); String value = entry.getValue(); fieldsNode.put(key, value); } } } private StackTraceElement extractCallerData(final ILoggingEvent event) { final StackTraceElement[] ste = event.getCallerData(); if (ste == null || ste.length == 0) { return DEFAULT_CALLER_DATA; } return ste[0]; } @Override public void close() throws IOException { write(LINE_SEPARATOR, outputStream); } public boolean isImmediateFlush() { return immediateFlush; } public void setImmediateFlush(boolean immediateFlush) { this.immediateFlush = immediateFlush; } }
package com.lifeix.pay.api.util; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * 订单信息收集日志 * * @author peter * */ public class PaymentOrderLog { protected final static Logger LOG = LoggerFactory.getLogger(PaymentOrderLog.class); public static void debug(String message) { LOG.debug(message); } public static void info(String message) { LOG.info(message); } public static void warn(String message) { LOG.warn(message); } public static void error(String message) { LOG.error(message); } public static void error(String message, Throwable e) { LOG.error(message, e); } }
上一篇: 大数据量高并发的数据库优化
下一篇: java 操作数据库备份