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.VirtualThreadStartEvent.class,
 75         jdk.internal.event.VirtualThreadEndEvent.class,
 76         jdk.internal.event.VirtualThreadSubmitFailedEvent.class,
 77         jdk.internal.event.X509CertificateEvent.class,
 78         jdk.internal.event.X509ValidationEvent.class,
 79         DirectBufferStatisticsEvent.class,
 80         InitialSecurityPropertyEvent.class,
 81         MethodTraceEvent.class,
 82         MethodTimingEvent.class,
 83     };
 84 
 85     private static final Runnable emitExceptionStatistics = JDKEvents::emitExceptionStatistics;
 86     private static final Runnable emitDirectBufferStatistics = JDKEvents::emitDirectBufferStatistics;
 87     private static final Runnable emitContainerConfiguration = JDKEvents::emitContainerConfiguration;
 88     private static final Runnable emitContainerCPUUsage = JDKEvents::emitContainerCPUUsage;
 89     private static final Runnable emitContainerCPUThrottling = JDKEvents::emitContainerCPUThrottling;
 90     private static final Runnable emitContainerMemoryUsage = JDKEvents::emitContainerMemoryUsage;
 91     private static final Runnable emitContainerIOUsage = JDKEvents::emitContainerIOUsage;
 92     private static final Runnable emitInitialSecurityProperties = JDKEvents::emitInitialSecurityProperties;
 93     private static final Runnable emitMethodTiming = JDKEvents::emitMethodTiming;
 94     private static Metrics containerMetrics = null;
 95     private static boolean initializationTriggered;
 96 
 97     @SuppressWarnings("unchecked")
 98     public static synchronized void initialize() {
 99         try {
100             if (initializationTriggered == false) {
101                 for (Class<?> eventClass : eventClasses) {
102                     MetadataRepository.getInstance().register((Class<? extends Event>) eventClass);
103                 }
104                 PeriodicEvents.addJavaEvent(jdk.internal.event.ExceptionStatisticsEvent.class, emitExceptionStatistics);
105                 PeriodicEvents.addJavaEvent(DirectBufferStatisticsEvent.class, emitDirectBufferStatistics);
106                 PeriodicEvents.addJavaEvent(InitialSecurityPropertyEvent.class, emitInitialSecurityProperties);
107                 PeriodicEvents.addJavaEvent(MethodTimingEvent.class, emitMethodTiming);
108 
109                 initializeContainerEvents();
110                 JFRTracing.enable();
111                 initializationTriggered = true;
112             }
113         } catch (Exception e) {
114             Logger.log(LogTag.JFR_SYSTEM, LogLevel.WARN, "Could not initialize JDK events. " + e.getMessage());
115         }
116     }
117 
118     private static void initializeContainerEvents() {
119         if (JVM.isContainerized() ) {
120             Logger.log(LogTag.JFR_SYSTEM, LogLevel.DEBUG, "JVM is containerized");
121             containerMetrics = Container.metrics();
122             if (containerMetrics != null) {
123                 Logger.log(LogTag.JFR_SYSTEM, LogLevel.DEBUG, "Container metrics are available");
124             }
125         }
126         // The registration of events and hooks are needed to provide metadata,
127         // even when not running in a container
128         registerEvent(ContainerConfigurationEvent.class);
129         registerEvent(ContainerCPUUsageEvent.class);
130         registerEvent(ContainerCPUThrottlingEvent.class);
131         registerEvent(ContainerMemoryUsageEvent.class);
132         registerEvent(ContainerIOUsageEvent.class);
133 
134         PeriodicEvents.addJavaEvent(ContainerConfigurationEvent.class, emitContainerConfiguration);
135         PeriodicEvents.addJavaEvent(ContainerCPUUsageEvent.class, emitContainerCPUUsage);
136         PeriodicEvents.addJavaEvent(ContainerCPUThrottlingEvent.class, emitContainerCPUThrottling);
137         PeriodicEvents.addJavaEvent(ContainerMemoryUsageEvent.class, emitContainerMemoryUsage);
138         PeriodicEvents.addJavaEvent(ContainerIOUsageEvent.class, emitContainerIOUsage);
139     }
140 
141     private static void registerEvent(Class<? extends jdk.internal.event.Event> eventClass) {
142         MetadataRepository.getInstance().register(eventClass);
143     }
144 
145     private static void emitExceptionStatistics() {
146         ThrowableTracer.emitStatistics();
147     }
148 
149     private static void emitContainerConfiguration() {
150         if (containerMetrics != null) {
151             ContainerConfigurationEvent t = new ContainerConfigurationEvent();
152             t.containerType = containerMetrics.getProvider();
153             t.cpuSlicePeriod = containerMetrics.getCpuPeriod();
154             t.cpuQuota = containerMetrics.getCpuQuota();
155             t.cpuShares = containerMetrics.getCpuShares();
156             t.effectiveCpuCount = containerMetrics.getEffectiveCpuCount();
157             t.memorySoftLimit = containerMetrics.getMemorySoftLimit();
158             t.memoryLimit = containerMetrics.getMemoryLimit();
159             t.swapMemoryLimit = containerMetrics.getMemoryAndSwapLimit();
160             t.hostTotalMemory = JVM.hostTotalMemory();
161             t.hostTotalSwapMemory = JVM.hostTotalSwapMemory();
162             t.commit();
163         }
164     }
165 
166     private static void emitContainerCPUUsage() {
167         if (containerMetrics != null) {
168             ContainerCPUUsageEvent event = new ContainerCPUUsageEvent();
169 
170             event.cpuTime = containerMetrics.getCpuUsage();
171             event.cpuSystemTime = containerMetrics.getCpuSystemUsage();
172             event.cpuUserTime = containerMetrics.getCpuUserUsage();
173             event.commit();
174         }
175     }
176     private static void emitContainerMemoryUsage() {
177         if (containerMetrics != null) {
178             ContainerMemoryUsageEvent event = new ContainerMemoryUsageEvent();
179 
180             event.memoryFailCount = containerMetrics.getMemoryFailCount();
181             event.memoryUsage = containerMetrics.getMemoryUsage();
182             event.swapMemoryUsage = containerMetrics.getMemoryAndSwapUsage();
183             event.commit();
184         }
185     }
186 
187     private static void emitContainerIOUsage() {
188         if (containerMetrics != null) {
189             ContainerIOUsageEvent event = new ContainerIOUsageEvent();
190 
191             event.serviceRequests = containerMetrics.getBlkIOServiceCount();
192             event.dataTransferred = containerMetrics.getBlkIOServiced();
193             event.commit();
194         }
195     }
196 
197     private static void emitContainerCPUThrottling() {
198         if (containerMetrics != null) {
199             ContainerCPUThrottlingEvent event = new ContainerCPUThrottlingEvent();
200 
201             event.cpuElapsedSlices = containerMetrics.getCpuNumPeriods();
202             event.cpuThrottledSlices = containerMetrics.getCpuNumThrottled();
203             event.cpuThrottledTime = containerMetrics.getCpuThrottledTime();
204             event.commit();
205         }
206     }
207 
208     public static void remove() {
209         PeriodicEvents.removeEvent(emitExceptionStatistics);
210         PeriodicEvents.removeEvent(emitDirectBufferStatistics);
211         PeriodicEvents.removeEvent(emitInitialSecurityProperties);
212         PeriodicEvents.removeEvent(emitMethodTiming);
213 
214         PeriodicEvents.removeEvent(emitContainerConfiguration);
215         PeriodicEvents.removeEvent(emitContainerCPUUsage);
216         PeriodicEvents.removeEvent(emitContainerCPUThrottling);
217         PeriodicEvents.removeEvent(emitContainerMemoryUsage);
218         PeriodicEvents.removeEvent(emitContainerIOUsage);
219     }
220 
221     private static void emitDirectBufferStatistics() {
222         DirectBufferStatisticsEvent e = new DirectBufferStatisticsEvent();
223         e.commit();
224     }
225 
226     private static void emitInitialSecurityProperties() {
227         Properties p = SharedSecrets.getJavaSecurityPropertiesAccess().getInitialProperties();
228         if (p != null) {
229             for (String key : p.stringPropertyNames()) {
230                 InitialSecurityPropertyEvent e = new InitialSecurityPropertyEvent();
231                 e.key = key;
232                 e.value = p.getProperty(key);
233                 e.commit();
234             }
235         }
236     }
237 
238     private static void emitMethodTiming() {
239         if (MethodSetting.isInitialized() && MethodTimingEvent.enabled()) {
240             PlatformTracer.emitTiming();
241         }
242     }
243 }