天天看點

log4j日志擴充---自定義PatternLayout

目前擴充log4j的日志一般使用擴充adaper的方法,這裡使用一種擴充PatternLayout方法.

log4j.rootLogger=debug, stdout, R

log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout

# Pattern to output the caller's file name and line number.
log4j.appender.stdout.layout.ConversionPattern=%5p [%t] (%F:%L) - %m%n

log4j.appender.R=org.apache.log4j.RollingFileAppender
log4j.appender.R.File=example.log

log4j.appender.R.MaxFileSize=100KB
# Keep one backup file
log4j.appender.R.MaxBackupIndex=1

log4j.appender.R.layout=org.apache.log4j.PatternLayout
log4j.appender.R.layout.ConversionPattern=%p %t %c - %m%n
           

這是log4j官網上的配置

請注意:

log4j.appender.stdout=org.apache.log4j.ConsoleAppender

log4j.appender.R.layout=org.apache.log4j.PatternLayout
           

注意到其實這是兩個類

那麼org.apache.log4j.ConsoleAppender可以自定義,思考是否可以自定義log4j.appender.R.layout=org.apache.log4j.PatternLayout

下載下傳官方檔案發現有這樣兩個類.

/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 * 
 *      http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package examples;

import org.apache.log4j.*;
import org.apache.log4j.helpers.PatternParser;

/**

  Example showing how to extend PatternLayout to recognize additional
  conversion characters.  
  
  <p>In this case MyPatternLayout recognizes %# conversion pattern. It
  outputs the value of an internal counter which is also incremented
  at each call.

  <p>See <a href=doc-files/MyPatternLayout.java><b>source</b></a> code
  for more details.

  @see MyPatternParser
  @see org.apache.log4j.PatternLayout
  @author Anders Kristensen 
*/
public class MyPatternLayout extends PatternLayout {
  public
  MyPatternLayout() {
    this(DEFAULT_CONVERSION_PATTERN);
  }

  public
  MyPatternLayout(String pattern) {
    super(pattern);
  }
    
  public
  PatternParser createPatternParser(String pattern) {
    return new MyPatternParser(
      pattern == null ? DEFAULT_CONVERSION_PATTERN : pattern);
  }
  
  public
  static void main(String[] args) {
    Layout layout = new MyPatternLayout("[counter=%.10#] - %m%n");
    Logger logger = Logger.getLogger("some.cat");
    logger.addAppender(new ConsoleAppender(layout, ConsoleAppender.SYSTEM_OUT));
    logger.debug("Hello, log");
    logger.info("Hello again...");    
  }
}
 
           
/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 * 
 *      http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package examples;

import org.apache.log4j.helpers.FormattingInfo;
import org.apache.log4j.helpers.PatternConverter;
import org.apache.log4j.helpers.PatternParser;
import org.apache.log4j.spi.LoggingEvent;

/**
  Example showing how to extend PatternParser to recognize additional
  conversion characters.  The examples shows that minimum and maximum
  width and alignment settings apply for "extension" conversion
  characters just as they do for PatternLayout recognized characters.
  
  <p>In this case MyPatternParser recognizes %# and outputs the value
  of an internal counter which is also incremented at each call.

  See <a href=doc-files/MyPatternParser.java><b>source</b></a> code
   for more details.
  
  @see org.apache.log4j.examples.MyPatternLayout
  @see org.apache.log4j.helpers.PatternParser
  @see org.apache.log4j.PatternLayout

  @author Anders Kristensen 
*/
public class MyPatternParser extends PatternParser {

  int counter = 0;

  public
  MyPatternParser(String pattern) {
    super(pattern);
  }
    
  public
  void finalizeConverter(char c) {
    if (c == '#') {
      addConverter(new UserDirPatternConverter(formattingInfo));
      currentLiteral.setLength(0);
    } else {
      super.finalizeConverter(c);
    }
  }
  
  private class UserDirPatternConverter extends PatternConverter {
    UserDirPatternConverter(FormattingInfo formattingInfo) {
      super(formattingInfo);
    }

    public
    String convert(LoggingEvent event) {
      return String.valueOf(++counter);
    }
  }  
}
           

直接粘過去找個類測試一下發現是可以使用的,顯示列印日志的行數

發現MyPatternLayout基本調用的是父類的方法 
           

繼續扒

public
  void finalizeConverter(char c) {
    if (c == '#') {
      addConverter(new UserDirPatternConverter(formattingInfo));
      currentLiteral.setLength(0);
    } else {
      super.finalizeConverter(c);
    }
  }
           

注意看這段代碼

發現字元為"#"的時候,建立了UserDirPatternConverter

推薦大家去看PatternParser這裡面有答案

給大家舉個例子

%#{MMMM}

使用extractOption()可以獲得MMMM

有了MMMM是不是就可以處理很多問題.

想一下,比如我們要在日志裡面列印公司的編号  orgId

那麼首先配置

log4j.appender.R.layout.ConversionPattern= %#{orgId}  %p %t %c - %m%n
           

這樣的話

if (c == '#') {
            String exs = super.extractOption();  //擷取orgId
            addConverter(new ExrPatternConverter(formattingInfo, exs));
            currentLiteral.setLength(0);

        } else {
            super.finalizeConverter(c);
        }
           

考慮orgId的指派問題

使用ThreadLocal

故完整的代碼

package com.yogapay.core;

import java.util.HashMap;
import java.util.Map;

import org.apache.log4j.helpers.FormattingInfo;
import org.apache.log4j.helpers.PatternConverter;
import org.apache.log4j.helpers.PatternParser;
import org.apache.log4j.spi.LoggingEvent;

public class ExPatternParser extends PatternParser {

	static final ThreadLocal<Map<String, Object>> TH_LOCAL = new ThreadLocal<Map<String, Object>>(){
		@Override
        protected HashMap<String, Object> initialValue() {
            return new HashMap<String, Object>();
        } 
	};

	public static void setCurrentValue(String key, Object value) {
		Map<String, Object> map = TH_LOCAL.get();
		map.put(key, value);
		
	}

	public ExPatternParser(String pattern) {
		super(pattern);
	}

	public void finalizeConverter(char c) {
		if (c == '#') {
			String exs = super.extractOption();
			addConverter(new ExrPatternConverter(formattingInfo, exs));
			currentLiteral.setLength(0);

		} else {
			super.finalizeConverter(c);
		}
	}

	private class ExrPatternConverter extends PatternConverter {

		private String cfg;

		ExrPatternConverter(FormattingInfo formattingInfo, String cfg) {
			super(formattingInfo);
			this.cfg = cfg;
		}

		public String convert(LoggingEvent event) {
			Map<String, Object> valueMap = TH_LOCAL.get();
			if (valueMap != null) {
				Object value = valueMap.get(cfg);
				if (value != null) {
					return String.valueOf(value);
				}
			}
			return "";
		}
	}
}
           
package com.yogapay.core;

import org.apache.log4j.*;
import org.apache.log4j.helpers.PatternParser;

public class ExPatternLayout extends PatternLayout {
	public ExPatternLayout() {
		this(DEFAULT_CONVERSION_PATTERN);
	}

	public ExPatternLayout(String pattern) {
		super(pattern);
	}

        @Override
	public PatternParser createPatternParser(String pattern) {
		return new ExPatternParser(pattern == null ? DEFAULT_CONVERSION_PATTERN : pattern);
	}
}
           
### set log levels ###
log4j.rootLogger = info,stdout

### 輸出到控制台 ###
log4j.appender.stdout = org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target = System.out
log4j.appender.stdout.layout = com.yogapay.core.ExPatternLayout
log4j.appender.stdout.layout.ConversionPattern = lgcNo:%#{orgId} %d{yyyy-MM-dd HH:mm:ss} [%t] %p [%c] - %m%n
           

到此擴充就完成呢!