001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017package org.apache.log4j.helpers; 018 019import org.apache.log4j.spi.LoggingEvent; 020import org.apache.log4j.pattern.LogEvent; 021 022import java.lang.reflect.Method; 023import java.util.Set; 024import java.io.ByteArrayOutputStream; 025import java.io.ObjectOutputStream; 026import java.io.ByteArrayInputStream; 027import java.io.ObjectInputStream; 028 029 030public final class MDCKeySetExtractor { 031 private final Method getKeySetMethod; 032 public static final MDCKeySetExtractor INSTANCE = 033 new MDCKeySetExtractor(); 034 035 036 private MDCKeySetExtractor() { 037 // 038 // log4j 1.2.15 and later will have method to get names 039 // of all keys in MDC 040 // 041 Method getMethod = null; 042 043 try { 044 getMethod = LoggingEvent.class.getMethod( 045 "getPropertyKeySet", null); 046 } catch(Exception ex) { 047 getMethod = null; 048 } 049 getKeySetMethod = getMethod; 050 051 } 052 053 public Set getPropertyKeySet(final LoggingEvent event) throws Exception { 054 // 055 // MDC keys are not visible prior to log4j 1.2.15 056 // 057 Set keySet = null; 058 if (getKeySetMethod != null) { 059 keySet = (Set) getKeySetMethod.invoke(event, null); 060 } else { 061 // 062 // for 1.2.14 and earlier could serialize and 063 // extract MDC content 064 ByteArrayOutputStream outBytes = new ByteArrayOutputStream(); 065 ObjectOutputStream os = new ObjectOutputStream(outBytes); 066 os.writeObject(event); 067 os.close(); 068 069 byte[] raw = outBytes.toByteArray(); 070 // 071 // bytes 6 and 7 should be the length of the original classname 072 // should be the same as our substitute class name 073 final String subClassName = LogEvent.class.getName(); 074 if (raw[6] == 0 || raw[7] == subClassName.length()) { 075 // 076 // manipulate stream to use our class name 077 // 078 for (int i = 0; i < subClassName.length(); i++) { 079 raw[8 + i] = (byte) subClassName.charAt(i); 080 } 081 ByteArrayInputStream inBytes = new ByteArrayInputStream(raw); 082 ObjectInputStream is = new ObjectInputStream(inBytes); 083 Object cracked = is.readObject(); 084 if (cracked instanceof LogEvent) { 085 keySet = ((LogEvent) cracked).getPropertyKeySet(); 086 } 087 is.close(); 088 } 089 } 090 return keySet; 091 } 092}