Pinpoint 분석 #3

2026. 8. 4. 00:19·개발 메모

1. Agent 부팅 흐름

전체 흐름

Target JVM
 -> PinpointBootStrap.premain(String, Instrumentation)
 -> PinpointBootStrap.start()
 -> PinpointStarter.start()
 -> AgentBootLoader.boot(AgentOption)
 -> new DefaultAgent(Map<String, Object>)
 -> DefaultAgent.start()
 -> DefaultApplicationContext.start()

큰 그림으로 보면 bootstraps/bootstrap은 JVM에 가장 먼저 붙는 얇은 부트스트랩 계층이고, 실제 agent runtime은 agent-module/profiler 아래의 DefaultAgent와 DefaultApplicationContext에서 시작된다.

1.1 JVM 진입점

파일:

  • agent-module/bootstraps/bootstrap/src/main/java/com/navercorp/pinpoint/bootstrap/PinpointBootStrap.java

핵심 메소드:

  • premain(String agentArgs, Instrumentation instrumentation)
  • start()

premain()은 JVM이 -javaagent 옵션으로 agent를 로딩할 때 호출하는 표준 Java Agent 진입점이다.

premain()
 -> DisableOptions.isBootDisabled()
 -> LoadState.start()
 -> new PinpointBootStrap(agentArgs, instrumentation)
 -> start()

여기서 하는 일은 많지 않다.

  • agent disable 여부 확인
  • 중복 시작 방지
  • JVM이 넘겨준 Instrumentation 객체 보관
  • 실제 시작 로직으로 위임

start()는 agent 설치 디렉터리를 찾고 bootstrap jar를 JVM bootstrap classloader에 추가한다.

start()
 -> JavaAgentPathResolver.resolveJavaAgentPath()
 -> ArgsParser.parse(agentArgs)
 -> AgentDirBaseClassPathResolver.resolve()
 -> appendToBootstrapClassLoader(...)
 -> new PinpointStarter(...)
 -> PinpointStarter.start()

중요한 메소드:

  • appendToBootstrapClassLoader(Instrumentation, BootDir)

이 메소드에서 instrumentation.appendToBootstrapClassLoaderSearch(jarFile)을 호출한다. Pinpoint가 계측 대상 애플리케이션보다 더 낮은 classloader 영역에 공용 bootstrap 클래스를 올리는 지점이다.

백엔드 관점으로 보면 이 단계는 Spring Boot의 main()보다 더 앞단이다. 애플리케이션 코드가 뜨기 전에 agent가 먼저 자기 실행 환경을 준비한다.

1.2 Agent classloader 생성

파일:

  • agent-module/bootstraps/bootstrap/src/main/java/com/navercorp/pinpoint/bootstrap/PinpointStarter.java

핵심 메소드:

  • start()
  • loadProperties()
  • resolveLib(AgentDirectory)
  • createClassLoader(String, URL[], ClassLoader, Properties)
  • createAgentOption(...)

PinpointStarter.start()는 실제 profiler jar들을 로딩할 agent 전용 classloader를 만든다.

PinpointStarter.start()
 -> loadProperties()
 -> DisableOptions.isDisabled(...)
 -> resolveLib(agentDirectory)
 -> createClassLoader("pinpoint.agent", urls, parentClassLoader, properties)
 -> loadModuleBootLoader(...)
 -> new AgentBootLoader(agentType.getClassName(), agentClassLoader)
 -> createAgentOption(...)
 -> agentBootLoader.boot(option)
 -> agent.start()
 -> agent.registerStopHandler()

여기서 만들어지는 AgentOption에는 agent runtime에 필요한 값들이 들어간다.

  • Instrumentation
  • config Properties
  • agent path
  • plugin jar 목록
  • bootstrap jar path 목록

agent-module/agent는 실제 Java 코드보다 배포 리소스와 설정을 담는 패키징 모듈에 가깝다. 실제 실행 코드는 agent-module/profiler에 있다.

1.3 DefaultAgent 생성

파일:

  • agent-module/bootstraps/bootstrap/src/main/java/com/navercorp/pinpoint/bootstrap/AgentBootLoader.java
  • agent-module/profiler/src/main/java/com/navercorp/pinpoint/profiler/DefaultAgent.java

핵심 메소드:

  • AgentBootLoader.boot(AgentOption)
  • DefaultAgent(Map<String, Object>)

AgentBootLoader.boot()는 agent classloader로 com.navercorp.pinpoint.profiler.Agent 인터페이스와 실제 구현 클래스를 로딩한다.

AgentBootLoader.boot()
 -> loadClass("com.navercorp.pinpoint.profiler.Agent")
 -> loadClass(bootClass)
 -> bootStrapClazz.getDeclaredConstructor(Map.class)
 -> newInstance(agentOption.toMap())

기본 agent type에서는 bootClass가 DefaultAgent 계열로 연결된다.

DefaultAgent 생성자는 agent runtime의 기본 환경을 만든다.

new DefaultAgent(map)
 -> AgentOption.of(map)
 -> ProfilerConfigLoader.load(properties)
 -> log config 준비
 -> ObjectName 생성
 -> AgentSystemConfig 저장
 -> Log4j2LoggingSystem.start()
 -> AgentContextOptionBuilder.build(...)
 -> 상태 INITIALIZING
 -> newApplicationContext(agentContextOption)

중요한 객체:

  • AgentOption: bootstrap 계층에서 넘어온 원본 실행 옵션
  • ProfilerConfig: pinpoint.config 계열 설정을 읽은 agent 설정 객체
  • ObjectName: agentId, agentName, applicationName, serviceName 등 agent identity
  • AgentContextOption: DefaultApplicationContext를 만들기 위한 정리된 옵션

백엔드 관점으로 보면 DefaultAgent 생성자는 서버 앱의 ApplicationContext 생성 직전까지 logging, config, identity를 준비하는 bootstrap layer다.

1.4 ApplicationContext 생성과 transformer 등록

파일:

  • agent-module/profiler/src/main/java/com/navercorp/pinpoint/profiler/DefaultAgent.java
  • agent-module/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/module/DefaultApplicationContext.java
  • agent-module/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/module/ApplicationContextModuleFactory.java

핵심 메소드:

  • DefaultAgent.newApplicationContext(AgentContextOption)
  • DefaultApplicationContext(AgentContextOption, ModuleFactory)
  • ApplicationContextModuleFactory.newModule(AgentContextOption)

DefaultAgent.newApplicationContext()는 Guice module factory를 찾고 DefaultApplicationContext를 만든다.

newApplicationContext()
 -> profilerConfig.readString("profiler.guice.module.factory", null)
 -> new DefaultModuleFactoryResolver(factoryClazzName)
 -> moduleFactoryResolver.resolve()
 -> new DefaultApplicationContext(agentOption, moduleFactory)

ApplicationContextModuleFactory.newModule()은 agent runtime에 필요한 Guice module을 합친다.

newModule()
 -> ConfigModule
 -> PluginModule
 -> ApplicationContextModule
 -> GrpcModule
 -> StatsModule
 -> ThriftStatsModule
 -> ExceptionTraceModule or DisabledExceptionTraceModule
 -> ErrorRecorderModule
 -> MicrometerModule

DefaultApplicationContext 생성자에서 중요한 일이 일어난다.

DefaultApplicationContext(...)
 -> Guice.createInjector(...)
 -> injector.getInstance(ProfilerConfig.class)
 -> injector.getInstance(InstrumentEngine.class)
 -> injector.getInstance(ClassFileTransformer.class)
 -> injector.getInstance(DynamicTransformTrigger.class)
 -> instrumentation.addTransformer(classFileTransformer, true)
 -> RPC-MODULE lifecycle start
 -> TraceContext 조회
 -> AgentInfoSender / AgentStatMonitor / MicrometerMonitor 조회

핵심 포인트:

  • ClassFileTransformer 등록은 DefaultApplicationContext.start()가 아니라 생성자에서 이미 일어난다.
  • Java 9 이상이면 module 처리를 위해 ClassFileTransformerModuleHandler와 ClassFileTransformerModuleWrap을 거친다.
  • bytecode dump 옵션이 켜져 있으면 BytecodeDumpTransformer.wrap(...)으로 transformer를 감싼다.

즉 "Pinpoint agent가 애플리케이션 코드를 계측할 준비가 됐다"는 것은 instrumentation.addTransformer(...)가 성공했다는 뜻이다.

1.5 Agent start와 shutdown hook

파일:

  • agent-module/profiler/src/main/java/com/navercorp/pinpoint/profiler/DefaultAgent.java
  • agent-module/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/module/DefaultApplicationContext.java

핵심 메소드:

  • DefaultAgent.start()
  • DefaultAgent.registerStopHandler()
  • DefaultAgent.close()
  • DefaultApplicationContext.start()
  • DefaultApplicationContext.close()

DefaultAgent.start()는 상태를 바꾸고 application context를 시작한다.

DefaultAgent.start()
 -> INITIALIZING 상태 확인
 -> RUNNING으로 변경
 -> applicationContext.start()
 -> printBanner()

DefaultApplicationContext.start()는 모니터와 agent 정보 전송을 시작한다.

DefaultApplicationContext.start()
 -> deadlockMonitor.start()
 -> agentInfoSender.start()
 -> agentStatMonitor.start()
 -> micrometerMonitor.start()

종료 처리는 registerStopHandler()에서 JVM shutdown hook으로 등록된다.

registerStopHandler()
 -> ShutdownHookRegisterProvider.get()
 -> new Thread(DefaultAgent.this.close())
 -> shutdownHookRegister.register(shutdownThread)

close()에서는 반대로 sender와 monitor를 멈추고 RPC module을 shutdown한다.

DefaultApplicationContext.close()
 -> agentInfoSender.stop()
 -> micrometerMonitor.stop()
 -> agentStatMonitor.stop()
 -> deadlockMonitor.stop()
 -> rpcModuleLifeCycle.shutdown()

Agent 부팅 문제를 디버깅할 때 보는 순서

  1. PinpointBootStrap.premain()에 진입했는가?
  2. DisableOptions 때문에 early return하지 않았는가?
  3. LoadState.start()가 중복 시작으로 막지 않았는가?
  4. JavaAgentPathResolver가 agent path를 제대로 찾았는가?
  5. AgentDirBaseClassPathResolver.resolve()가 agent directory를 검증했는가?
  6. appendToBootstrapClassLoader()가 bootstrap jar를 append했는가?
  7. PinpointStarter.createClassLoader()가 pinpoint.agent classloader를 만들었는가?
  8. AgentBootLoader.boot()가 DefaultAgent를 생성했는가?
  9. DefaultApplicationContext 생성 중 instrumentation.addTransformer(...)가 호출됐는가?
  10. DefaultApplicationContext.start()에서 sender와 monitor가 시작됐는가?

'개발 메모' 카테고리의 다른 글

Pinpoint 분석 #5  (0) 2026.08.04
Pinpoint 분석 #4  (0) 2026.08.04
Pinpoint 분석 #2  (0) 2026.08.04
Pinpoint 분석 #1  (0) 2026.08.04
멀티 스레딩에서 자원 공유하기  (0) 2024.11.16
'개발 메모' 카테고리의 다른 글
  • Pinpoint 분석 #5
  • Pinpoint 분석 #4
  • Pinpoint 분석 #2
  • Pinpoint 분석 #1
csb0710
csb0710
  • csb0710
    데모장
    csb0710
  • 전체
    오늘
    어제
    • 분류 전체보기 (60)
      • 스프링부트 메모 (7)
      • 개발 메모 (10)
      • 클라우드 메모 (10)
      • 설치&설정 메모 (2)
      • 알고리즘 메모 (18)
      • 인턴 메모 (7)
      • 데이터베이스 메모 (3)
      • 책 메모 (1)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

  • 공지사항

  • 인기 글

  • 태그

    디비설치
    디비설정
    코드트리
    자동 답변 봇
    submodule
    알고리즘
    백준
    HBase
    그리디
    오블완
    이지퍼블리싱
    .gitmodules
    스프링부트
    서버생성
    코드트리조별과제
    GitHub
    서버배포
    코딩테스트
    서버 연결
    티스토리챌린지
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.2
csb0710
Pinpoint 분석 #3
상단으로

티스토리툴바