1 /*
  2  * Copyright (c) 2016, 2025, Oracle and/or its affiliates. All rights reserved.
  3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  4  *
  5  * This code is free software; you can redistribute it and/or modify it
  6  * under the terms of the GNU General Public License version 2 only, as
  7  * published by the Free Software Foundation.  Oracle designates this
  8  * particular file as subject to the "Classpath" exception as provided
  9  * by Oracle in the LICENSE file that accompanied this code.
 10  *
 11  * This code is distributed in the hope that it will be useful, but WITHOUT
 12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 14  * version 2 for more details (a copy is included in the LICENSE file that
 15  * accompanied this code).
 16  *
 17  * You should have received a copy of the GNU General Public License version
 18  * 2 along with this work; if not, write to the Free Software Foundation,
 19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 20  *
 21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 22  * or visit www.oracle.com if you need additional information or have any
 23  * questions.
 24  */
 25 
 26 package jdk.jfr.internal;
 27 
 28 import java.util.Properties;
 29 
 30 import jdk.internal.access.SharedSecrets;
 31 import jdk.internal.event.JFRTracing;
 32 import jdk.internal.event.ThrowableTracer;
 33 import jdk.internal.platform.Container;
 34 import jdk.internal.platform.Metrics;
 35 import jdk.jfr.Event;
 36 import jdk.jfr.events.ActiveRecordingEvent;
 37 import jdk.jfr.events.ActiveSettingEvent;
 38 import jdk.jfr.events.ContainerCPUThrottlingEvent;
 39 import jdk.jfr.events.ContainerCPUUsageEvent;
 40 import jdk.jfr.events.ContainerConfigurationEvent;
 41 import jdk.jfr.events.ContainerIOUsageEvent;
 42 import jdk.jfr.events.ContainerMemoryUsageEvent;
 43 import jdk.jfr.events.DirectBufferStatisticsEvent;
 44 import jdk.jfr.events.InitialSecurityPropertyEvent;
 45 import jdk.jfr.events.MethodTimingEvent;
 46 import jdk.jfr.events.MethodTraceEvent;
 47 import jdk.jfr.internal.periodic.PeriodicEvents;
 48 import jdk.jfr.internal.settings.MethodSetting;
 49 import jdk.jfr.internal.tracing.PlatformTracer;
 50 import jdk.jfr.tracing.MethodTracer;
 51 
 52 public final class JDKEvents {
 53 
 54     private static final Class<?>[] eventClasses = {
 55         ActiveSettingEvent.class,
 56         ActiveRecordingEvent.class,
 57         // jdk.internal.event.* classes need their mirror
 58         // event class to be listed in the MirrorEvents class.
 59         jdk.internal.event.DeserializationEvent.class,
 60         jdk.internal.event.ErrorThrownEvent.class,
 61         jdk.internal.event.ExceptionStatisticsEvent.class,
 62         jdk.internal.event.ExceptionThrownEvent.class,
 63         jdk.internal.event.FileForceEvent.class,
 64         jdk.internal.event.FileReadEvent.class,
 65         jdk.internal.event.FileWriteEvent.class,
 66         jdk.internal.event.ProcessStartEvent.class,
 67         jdk.internal.event.SecurityPropertyModificationEvent.class,
 68         jdk.internal.event.SecurityProviderServiceEvent.class,
 69         jdk.internal.event.SerializationMisdeclarationEvent.class,
 70         jdk.internal.event.SocketReadEvent.class,
 71         jdk.internal.event.SocketWriteEvent.class,
 72         jdk.internal.event.ThreadSleepEvent.class,
 73         jdk.internal.event.TLSHandshakeEvent.class,
 74         jdk.internal.event.VirtualThreadParkEvent.class,
 75         jdk.internal.event.VirtualThreadStartEvent.class,
 76         jdk.internal.event.VirtualThreadEndEvent.class,
 77         jdk.internal.event.VirtualThreadSubmitFailedEvent.class,
 78         jdk.internal.event.X509CertificateEvent.class,
 79         jdk.internal.event.X509ValidationEvent.class,
 80         DirectBufferStatisticsEvent.class,
 81         InitialSecurityPropertyEvent.class,
 82         MethodTraceEvent.class,
 83         MethodTimingEvent.class,
 84     };
 85 
 86     private static final Runnable emitExceptionStatistics = JDKEvents::emitExceptionStatistics;
 87     private static final Runnable emitDirectBufferStatistics = JDKEvents::emitDirectBufferStatistics;
 88     private static final Runnable emitContainerConfiguration = JDKEvents::emitContainerConfiguration;
 89     private static final Runnable emitContainerCPUUsage = JDKEvents::emitContainerCPUUsage;
 90     private static final Runnable emitContainerCPUThrottling = JDKEvents::emitContainerCPUThrottling;
 91     private static final Runnable emitContainerMemoryUsage = JDKEvents::emitContainerMemoryUsage;
 92     private static final Runnable emitContainerIOUsage = JDKEvents::emitContainerIOUsage;
 93     private static final Runnable emitInitialSecurityProperties = JDKEvents::emitInitialSecurityProperties;
 94     private static final Runnable emitMethodTiming = JDKEvents::emitMethodTiming;
 95     private static Metrics containerMetrics = null;
 96     private static boolean initializationTriggered;
 97 
 98     @SuppressWarnings("unchecked")
 99     public static synchronized void initialize() {
100         try {
101             if (initializationTriggered == false) {
102                 for (Class<?> eventClass : eventClasses) {
103                     MetadataRepository.getInstance().register((Class<? extends Event>) eventClass);
104                 }
105                 PeriodicEvents.addJavaEvent(jdk.internal.event.ExceptionStatisticsEvent.class, emitExceptionStatistics);
106                 PeriodicEvents.addJavaEvent(DirectBufferStatisticsEvent.class, emitDirectBufferStatistics);
107                 PeriodicEvents.addJavaEvent(InitialSecurityPropertyEvent.class, emitInitialSecurityProperties);
108                 PeriodicEvents.addJavaEvent(MethodTimingEvent.class, emitMethodTiming);
109 
110                 initializeContainerEvents();
111                 JFRTracing.enable();
112                 initializationTriggered = true;
113             }
114         } catch (Exception e) {
115             Logger.log(LogTag.JFR_SYSTEM, LogLevel.WARN, "Could not initialize JDK events. " + e.getMessage());
116         }
117     }
118 
119     private static void initializeContainerEvents() {
120         if (JVM.isContainerized() ) {
121             Logger.log(LogTag.JFR_SYSTEM, LogLevel.DEBUG, "JVM is containerized");
122             containerMetrics = Container.metrics();
123             if (containerMetrics != null) {
124                 Logger.log(LogTag.JFR_SYSTEM, LogLevel.DEBUG, "Container metrics are available");
125             }
126         }
127         // The registration of events and hooks are needed to provide metadata,
128         // even when not running in a container
129         registerEvent(ContainerConfigurationEvent.class);
130         registerEvent(ContainerCPUUsageEvent.class);
131         registerEvent(ContainerCPUThrottlingEvent.class);
132         registerEvent(ContainerMemoryUsageEvent.class);
133         registerEvent(ContainerIOUsageEvent.class);
134 
135         PeriodicEvents.addJavaEvent(ContainerConfigurationEvent.class, emitContainerConfiguration);
136         PeriodicEvents.addJavaEvent(ContainerCPUUsageEvent.class, emitContainerCPUUsage);
137         PeriodicEvents.addJavaEvent(ContainerCPUThrottlingEvent.class, emitContainerCPUThrottling);
138         PeriodicEvents.addJavaEvent(ContainerMemoryUsageEvent.class, emitContainerMemoryUsage);
139         PeriodicEvents.addJavaEvent(ContainerIOUsageEvent.class, emitContainerIOUsage);
140     }
141 
142     private static void registerEvent(Class<? extends jdk.internal.event.Event> eventClass) {
143         MetadataRepository.getInstance().register(eventClass);
144     }
145 
146     private static void emitExceptionStatistics() {
147         ThrowableTracer.emitStatistics();
148     }
149 
150     private static void emitContainerConfiguration() {
151         if (containerMetrics != null) {
152             ContainerConfigurationEvent t = new ContainerConfigurationEvent();
153             t.containerType = containerMetrics.getProvider();
154             t.cpuSlicePeriod = containerMetrics.getCpuPeriod();
155             t.cpuQuota = containerMetrics.getCpuQuota();
156             t.cpuShares = containerMetrics.getCpuShares();
157             t.effectiveCpuCount = containerMetrics.getEffectiveCpuCount();
158             t.memorySoftLimit = containerMetrics.getMemorySoftLimit();
159             t.memoryLimit = containerMetrics.getMemoryLimit();
160             t.swapMemoryLimit = containerMetrics.getMemoryAndSwapLimit();
161             t.hostTotalMemory = JVM.hostTotalMemory();
162             t.hostTotalSwapMemory = JVM.hostTotalSwapMemory();
163             t.commit();
164         }
165     }
166 
167     private static void emitContainerCPUUsage() {
168         if (containerMetrics != null) {
169             ContainerCPUUsageEvent event = new ContainerCPUUsageEvent();
170 
171             event.cpuTime = containerMetrics.getCpuUsage();
172             event.cpuSystemTime = containerMetrics.getCpuSystemUsage();
173             event.cpuUserTime = containerMetrics.getCpuUserUsage();
174             event.commit();
175         }
176     }
177     private static void emitContainerMemoryUsage() {
178         if (containerMetrics != null) {
179             ContainerMemoryUsageEvent event = new ContainerMemoryUsageEvent();
180 
181             event.memoryFailCount = containerMetrics.getMemoryFailCount();
182             event.memoryUsage = containerMetrics.getMemoryUsage();
183             event.swapMemoryUsage = containerMetrics.getMemoryAndSwapUsage();
184             event.commit();
185         }
186     }
187 
188     private static void emitContainerIOUsage() {
189         if (containerMetrics != null) {
190             ContainerIOUsageEvent event = new ContainerIOUsageEvent();
191 
192             event.serviceRequests = containerMetrics.getBlkIOServiceCount();
193             event.dataTransferred = containerMetrics.getBlkIOServiced();
194             event.commit();
195         }
196     }
197 
198     private static void emitContainerCPUThrottling() {
199         if (containerMetrics != null) {
200             ContainerCPUThrottlingEvent event = new ContainerCPUThrottlingEvent();
201 
202             event.cpuElapsedSlices = containerMetrics.getCpuNumPeriods();
203             event.cpuThrottledSlices = containerMetrics.getCpuNumThrottled();
204             event.cpuThrottledTime = containerMetrics.getCpuThrottledTime();
205             event.commit();
206         }
207     }
208 
209     public static void remove() {
210         PeriodicEvents.removeEvent(emitExceptionStatistics);
211         PeriodicEvents.removeEvent(emitDirectBufferStatistics);
212         PeriodicEvents.removeEvent(emitInitialSecurityProperties);
213         PeriodicEvents.removeEvent(emitMethodTiming);
214 
215         PeriodicEvents.removeEvent(emitContainerConfiguration);
216         PeriodicEvents.removeEvent(emitContainerCPUUsage);
217         PeriodicEvents.removeEvent(emitContainerCPUThrottling);
218         PeriodicEvents.removeEvent(emitContainerMemoryUsage);
219         PeriodicEvents.removeEvent(emitContainerIOUsage);
220     }
221 
222     private static void emitDirectBufferStatistics() {
223         DirectBufferStatisticsEvent e = new DirectBufferStatisticsEvent();
224         e.commit();
225     }
226 
227     private static void emitInitialSecurityProperties() {
228         Properties p = SharedSecrets.getJavaSecurityPropertiesAccess().getInitialProperties();
229         if (p != null) {
230             for (String key : p.stringPropertyNames()) {
231                 InitialSecurityPropertyEvent e = new InitialSecurityPropertyEvent();
232                 e.key = key;
233                 e.value = p.getProperty(key);
234                 e.commit();
235             }
236         }
237     }
238 
239     private static void emitMethodTiming() {
240         if (MethodSetting.isInitialized() && MethodTimingEvent.enabled()) {
241             PlatformTracer.emitTiming();
242         }
243     }
244 }