/*
* 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.profiler;
import com.navercorp.pinpoint.ProductInfo;
import com.navercorp.pinpoint.bootstrap.Agent;
import com.navercorp.pinpoint.bootstrap.AgentOption;
import com.navercorp.pinpoint.bootstrap.config.ProfilerConfig;
import com.navercorp.pinpoint.bootstrap.interceptor.InterceptorInvokerHelper;
import com.navercorp.pinpoint.bootstrap.logging.PLogger;
import com.navercorp.pinpoint.bootstrap.logging.PLoggerBinder;
import com.navercorp.pinpoint.bootstrap.logging.PLoggerFactory;
import com.navercorp.pinpoint.common.service.ServiceTypeRegistryService;
import com.navercorp.pinpoint.profiler.context.module.ApplicationContext;
import com.navercorp.pinpoint.profiler.context.module.DefaultApplicationContext;
import com.navercorp.pinpoint.profiler.util.SystemPropertyDumper;
import com.navercorp.pinpoint.profiler.interceptor.registry.DefaultInterceptorRegistryBinder;
import com.navercorp.pinpoint.profiler.interceptor.registry.InterceptorRegistryBinder;
import com.navercorp.pinpoint.profiler.logging.Slf4jLoggerBinder;
import com.navercorp.pinpoint.rpc.ClassPreLoader;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* @author emeroad
* @author koo.taejin
* @author hyungil.jeong
*/
public class DefaultAgent implements Agent {
private final Logger logger = LoggerFactory.getLogger(this.getClass());
private final PLoggerBinder binder;
private final ProfilerConfig profilerConfig;
private final ApplicationContext applicationContext;
private final Object agentStatusLock = new Object();
private volatile AgentStatus agentStatus;
private final InterceptorRegistryBinder interceptorRegistryBinder;
private final ServiceTypeRegistryService serviceTypeRegistryService;
static {
// Preload classes related to pinpoint-rpc module.
ClassPreLoader.preload();
}
public DefaultAgent(AgentOption agentOption) {
this(agentOption, createInterceptorRegistry(agentOption));
}
public static InterceptorRegistryBinder createInterceptorRegistry(AgentOption agentOption) {
final int interceptorSize = getInterceptorSize(agentOption);
return new DefaultInterceptorRegistryBinder(interceptorSize);
}
private static int getInterceptorSize(AgentOption agentOption) {
if (agentOption == null) {
return DefaultInterceptorRegistryBinder.DEFAULT_MAX;
}
final ProfilerConfig profilerConfig = agentOption.getProfilerConfig();
return profilerConfig.getInterceptorRegistrySize();
}
public DefaultAgent(AgentOption agentOption, final InterceptorRegistryBinder interceptorRegistryBinder) {
if (agentOption == null) {
throw new NullPointerException("agentOption must not be null");
}
if (agentOption.getInstrumentation() == null) {
throw new NullPointerException("instrumentation must not be null");
}
if (agentOption.getProfilerConfig() == null) {
throw new NullPointerException("profilerConfig must not be null");
}
if (agentOption.getServiceTypeRegistryService() == null) {
throw new NullPointerException("serviceTypeRegistryService must not be null");
}
if (interceptorRegistryBinder == null) {
throw new NullPointerException("interceptorRegistryBinder must not be null");
}
logger.info("AgentOption:{}", agentOption);
this.binder = new Slf4jLoggerBinder();
bindPLoggerFactory(this.binder);
this.interceptorRegistryBinder = interceptorRegistryBinder;
interceptorRegistryBinder.bind();
this.serviceTypeRegistryService = agentOption.getServiceTypeRegistryService();
dumpSystemProperties();
dumpConfig(agentOption.getProfilerConfig());
changeStatus(AgentStatus.INITIALIZING);
this.profilerConfig = agentOption.getProfilerConfig();
this.applicationContext = newApplicationContext(agentOption, interceptorRegistryBinder);
InterceptorInvokerHelper.setPropagateException(profilerConfig.isPropagateInterceptorException());
}
protected ApplicationContext newApplicationContext(AgentOption agentOption, InterceptorRegistryBinder interceptorRegistryBinder) {
return new DefaultApplicationContext(agentOption, interceptorRegistryBinder);
}
protected ApplicationContext getApplicationContext() {
return applicationContext;
}
private void dumpSystemProperties() {
SystemPropertyDumper dumper = new SystemPropertyDumper();
dumper.dump();
}
private void dumpConfig(ProfilerConfig profilerConfig) {
if (logger.isInfoEnabled()) {
logger.info("{}\n{}", "dumpConfig", profilerConfig);
}
}
private void changeStatus(AgentStatus status) {
this.agentStatus = status;
if (logger.isDebugEnabled()) {
logger.debug("Agent status is changed. {}", status);
}
}
private void bindPLoggerFactory(PLoggerBinder binder) {
final String binderClassName = binder.getClass().getName();
PLogger pLogger = binder.getLogger(binder.getClass().getName());
pLogger.info("PLoggerFactory.initialize() bind:{} cl:{}", binderClassName, binder.getClass().getClassLoader());
// Set binder to static LoggerFactory
// Should we unset binder at shutdown hook or stop()?
PLoggerFactory.initialize(binder);
}
public ServiceTypeRegistryService getServiceTypeRegistryService() {
return serviceTypeRegistryService;
}
@Override
public void start() {
synchronized (agentStatusLock) {
if (this.agentStatus == AgentStatus.INITIALIZING) {
changeStatus(AgentStatus.RUNNING);
} else {
logger.warn("Agent already started.");
return;
}
}
logger.info("Starting {} Agent.", ProductInfo.NAME);
this.applicationContext.start();
}
@Override
public void stop() {
stop(false);
}
public void stop(boolean staticResourceCleanup) {
synchronized (agentStatusLock) {
if (this.agentStatus == AgentStatus.RUNNING) {
changeStatus(AgentStatus.STOPPED);
} else {
logger.warn("Cannot stop agent. Current status = [{}]", this.agentStatus);
return;
}
}
logger.info("Stopping {} Agent.", ProductInfo.NAME);
this.applicationContext.close();
// for testcase
if (staticResourceCleanup) {
PLoggerFactory.unregister(this.binder);
this.interceptorRegistryBinder.unbind();
}
}
}