/*
* Copyright 2014 NAVER Corp.
*
* Licensed 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 com.navercorp.pinpoint.plugin.log4j;
import java.security.ProtectionDomain;
import com.navercorp.pinpoint.bootstrap.instrument.InstrumentClass;
import com.navercorp.pinpoint.bootstrap.instrument.InstrumentException;
import com.navercorp.pinpoint.bootstrap.instrument.Instrumentor;
import com.navercorp.pinpoint.bootstrap.instrument.transformer.TransformCallback;
import com.navercorp.pinpoint.bootstrap.instrument.transformer.TransformTemplate;
import com.navercorp.pinpoint.bootstrap.instrument.transformer.TransformTemplateAware;
import com.navercorp.pinpoint.bootstrap.logging.PLogger;
import com.navercorp.pinpoint.bootstrap.logging.PLoggerFactory;
import com.navercorp.pinpoint.bootstrap.plugin.ProfilerPlugin;
import com.navercorp.pinpoint.bootstrap.plugin.ProfilerPluginSetupContext;
/**
* This modifier support log4j 1.2.15 version, or greater.
* Because under 1.2.15 version is not exist MDC function and the number of constructor is different
* and under 1.2.15 version is too old.
* For reference 1.2.14 version release on Sep. 2006.
* Refer to url http://mvnrepository.com/artifact/log4j/log4j for detail.
*
* @author minwoo.jung
*/
public class Log4jPlugin implements ProfilerPlugin, TransformTemplateAware {
private final PLogger logger = PLoggerFactory.getLogger(getClass());
private TransformTemplate transformTemplate;
@Override
public void setup(ProfilerPluginSetupContext context) {
final Log4jConfig config = new Log4jConfig(context.getConfig());
if (logger.isInfoEnabled()) {
logger.info("Log4jPlugin config:{}", config);
}
if (!config.isLog4jLoggingTransactionInfo()) {
logger.info("Log4j plugin is not executed because log4j transform enable config value is false.");
return;
}
transformTemplate.transform("org.apache.log4j.spi.LoggingEvent", new TransformCallback() {
@Override
public byte[] doInTransform(Instrumentor instrumentor, ClassLoader loader, String className, Class<?> classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws InstrumentException {
InstrumentClass mdcClass = instrumentor.getInstrumentClass(loader, "org.apache.log4j.MDC", null);
if (mdcClass == null) {
logger.warn("Can not modify. Because org.apache.log4j.MDC does not exist.");
return null;
}
if (!mdcClass.hasMethod("put", "java.lang.String", "java.lang.Object")) {
logger.warn("Can not modify. Because put method does not exist at org.apache.log4j.MDC class.");
return null;
}
if (!mdcClass.hasMethod("remove", "java.lang.String")) {
logger.warn("Can not modify. Because remove method does not exist at org.apache.log4j.MDC class.");
return null;
}
InstrumentClass target = instrumentor.getInstrumentClass(loader, className, classfileBuffer);
if (!target.hasConstructor("java.lang.String", "org.apache.log4j.Category", "org.apache.log4j.Priority", "java.lang.Object", "java.lang.Throwable")) {
logger.warn("Can not modify. Because constructor to modify not exist at org.apache.log4j.MDC class."
+ "\nThere is a strong presumption that your application use under version 1.2.14 log4j."
+ "\nconstructor prototype : LoggingEvent(String fqnOfCategoryClass, Category logger, Priority level, Object message, Throwable throwable);");
return null;
}
if (!target.hasConstructor("java.lang.String", "org.apache.log4j.Category", "long", "org.apache.log4j.Priority", "java.lang.Object", "java.lang.Throwable")) {
logger.warn("Can not modify. Because constructor to modify not exist at org.apache.log4j.MDC class."
+ "\nThere is a strong presumption that your application use under version 1.2.14 log4j."
+ "\nconstructor prototype : LoggingEvent(String fqnOfCategoryClass, Category logger, long timeStamp, Priority level, Object message, Throwable throwable);");
return null;
}
if (!target.hasConstructor("java.lang.String", "org.apache.log4j.Category", "long", "org.apache.log4j.Level", "java.lang.Object", "java.lang.String", "org.apache.log4j.spi.ThrowableInformation", "java.lang.String", "org.apache.log4j.spi.LocationInfo", "java.util.Map")) {
logger.warn("Can not modify. Because constructor to modify not exist at org.apache.log4j.MDC class. "
+ "\nThere is a strong presumption that your application use under version 1.2.14 log4j."
+ "\nconstructor prototype : LoggingEvent(final String fqnOfCategoryClass, final Category logger, final long timeStamp, final Level level, final Object message, final String threadName, final ThrowableInformation throwable, final String ndc, final LocationInfo info, final java.util.Map properties);");
return null;
}
target.addInterceptor("com.navercorp.pinpoint.plugin.log4j.interceptor.LoggingEventOfLog4jInterceptor");
return target.toBytecode();
}
});
}
@Override
public void setTransformTemplate(TransformTemplate transformTemplate) {
this.transformTemplate = transformTemplate;
}
}