1 /*
  2  * Copyright (c) 2016, 2024, 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.internal.periodic.PeriodicEvents;
 46 
 47 public final class JDKEvents {
 48 
 49     private static final Class<?>[] eventClasses = {
 50         ActiveSettingEvent.class,
 51         ActiveRecordingEvent.class,
 52         // jdk.internal.event.* classes need their mirror
 53         // event class to be listed in the MirrorEvents class.
 54         jdk.internal.event.DeserializationEvent.class,
 55         jdk.internal.event.ErrorThrownEvent.class,
 56         jdk.internal.event.ExceptionStatisticsEvent.class,
 57         jdk.internal.event.ExceptionThrownEvent.class,
 58         jdk.internal.event.FileForceEvent.class,
 59         jdk.internal.event.FileReadEvent.class,
 60         jdk.internal.event.FileWriteEvent.class,
 61         jdk.internal.event.ProcessStartEvent.class,
 62         jdk.internal.event.SecurityPropertyModificationEvent.class,
 63         jdk.internal.event.SecurityProviderServiceEvent.class,
 64         jdk.internal.event.SerializationMisdeclarationEvent.class,
 65         jdk.internal.event.SocketReadEvent.class,
 66         jdk.internal.event.SocketWriteEvent.class,
 67         jdk.internal.event.ThreadSleepEvent.class,
 68         jdk.internal.event.TLSHandshakeEvent.class,
 69         jdk.internal.event.VirtualThreadStartEvent.class,
 70         jdk.internal.event.VirtualThreadEndEvent.class,
 71         jdk.internal.event.VirtualThreadPinnedEvent.class,
 72         jdk.internal.event.VirtualThreadSubmitFailedEvent.class,
 73         jdk.internal.event.X509CertificateEvent.class,
 74         jdk.internal.event.X509ValidationEvent.class,
 75         DirectBufferStatisticsEvent.class,
 76         InitialSecurityPropertyEvent.class,
 77     };
 78 
 79     private static final Runnable emitExceptionStatistics = JDKEvents::emitExceptionStatistics;
 80     private static final Runnable emitDirectBufferStatistics = JDKEvents::emitDirectBufferStatistics;
 81     private static final Runnable emitContainerConfiguration = JDKEvents::emitContainerConfiguration;
 82     private static final Runnable emitContainerCPUUsage = JDKEvents::emitContainerCPUUsage;
 83     private static final Runnable emitContainerCPUThrottling = JDKEvents::emitContainerCPUThrottling;
 84     private static final Runnable emitContainerMemoryUsage = JDKEvents::emitContainerMemoryUsage;
 85     private static final Runnable emitContainerIOUsage = JDKEvents::emitContainerIOUsage;
 86     private static final Runnable emitInitialSecurityProperties = JDKEvents::emitInitialSecurityProperties;
 87     private static Metrics containerMetrics = null;
 88     private static boolean initializationTriggered;
 89 
 90     @SuppressWarnings("unchecked")
 91     public static synchronized void initialize() {
 92         try {
 93             if (initializationTriggered == false) {
 94                 for (Class<?> eventClass : eventClasses) {
 95                     SecuritySupport.registerEvent((Class<? extends Event>) eventClass);
 96                 }
 97                 PeriodicEvents.addJDKEvent(jdk.internal.event.ExceptionStatisticsEvent.class, emitExceptionStatistics);
 98                 PeriodicEvents.addJDKEvent(DirectBufferStatisticsEvent.class, emitDirectBufferStatistics);
 99                 PeriodicEvents.addJDKEvent(InitialSecurityPropertyEvent.class, emitInitialSecurityProperties);
100 
101                 initializeContainerEvents();
102                 JFRTracing.enable();
103                 initializationTriggered = true;
104             }
105         } catch (Exception e) {
106             Logger.log(LogTag.JFR_SYSTEM, LogLevel.WARN, "Could not initialize JDK events. " + e.getMessage());
107         }
108     }
109 
110     private static void initializeContainerEvents() {
111         if (JVM.isContainerized() ) {
112             Logger.log(LogTag.JFR_SYSTEM, LogLevel.DEBUG, "JVM is containerized");
113             containerMetrics = Container.metrics();
114             if (containerMetrics != null) {
115                 Logger.log(LogTag.JFR_SYSTEM, LogLevel.DEBUG, "Container metrics are available");
116             }
117         }
118         // The registration of events and hooks are needed to provide metadata,
119         // even when not running in a container
120         SecuritySupport.registerEvent(ContainerConfigurationEvent.class);
121         SecuritySupport.registerEvent(ContainerCPUUsageEvent.class);
122         SecuritySupport.registerEvent(ContainerCPUThrottlingEvent.class);
123         SecuritySupport.registerEvent(ContainerMemoryUsageEvent.class);
124         SecuritySupport.registerEvent(ContainerIOUsageEvent.class);
125 
126         PeriodicEvents.addJDKEvent(ContainerConfigurationEvent.class, emitContainerConfiguration);
127         PeriodicEvents.addJDKEvent(ContainerCPUUsageEvent.class, emitContainerCPUUsage);
128         PeriodicEvents.addJDKEvent(ContainerCPUThrottlingEvent.class, emitContainerCPUThrottling);
129         PeriodicEvents.addJDKEvent(ContainerMemoryUsageEvent.class, emitContainerMemoryUsage);
130         PeriodicEvents.addJDKEvent(ContainerIOUsageEvent.class, emitContainerIOUsage);
131     }
132 
133     private static void emitExceptionStatistics() {
134         ThrowableTracer.emitStatistics();
135     }
136 
137     private static void emitContainerConfiguration() {
138         if (containerMetrics != null) {
139             ContainerConfigurationEvent t = new ContainerConfigurationEvent();
140             t.containerType = containerMetrics.getProvider();
141             t.cpuSlicePeriod = containerMetrics.getCpuPeriod();
142             t.cpuQuota = containerMetrics.getCpuQuota();
143             t.cpuShares = containerMetrics.getCpuShares();
144             t.effectiveCpuCount = containerMetrics.getEffectiveCpuCount();
145             t.memorySoftLimit = containerMetrics.getMemorySoftLimit();
146             t.memoryLimit = containerMetrics.getMemoryLimit();
147             t.swapMemoryLimit = containerMetrics.getMemoryAndSwapLimit();
148             t.hostTotalMemory = JVM.hostTotalMemory();
149             t.hostTotalSwapMemory = JVM.hostTotalSwapMemory();
150             t.commit();
151         }
152     }
153 
154     private static void emitContainerCPUUsage() {
155         if (containerMetrics != null) {
156             ContainerCPUUsageEvent event = new ContainerCPUUsageEvent();
157 
158             event.cpuTime = containerMetrics.getCpuUsage();
159             event.cpuSystemTime = containerMetrics.getCpuSystemUsage();
160             event.cpuUserTime = containerMetrics.getCpuUserUsage();
161             event.commit();
162         }
163     }
164     private static void emitContainerMemoryUsage() {
165         if (containerMetrics != null) {
166             ContainerMemoryUsageEvent event = new ContainerMemoryUsageEvent();
167 
168             event.memoryFailCount = containerMetrics.getMemoryFailCount();
169             event.memoryUsage = containerMetrics.getMemoryUsage();
170             event.swapMemoryUsage = containerMetrics.getMemoryAndSwapUsage();
171             event.commit();
172         }
173     }
174 
175     private static void emitContainerIOUsage() {
176         if (containerMetrics != null) {
177             ContainerIOUsageEvent event = new ContainerIOUsageEvent();
178 
179             event.serviceRequests = containerMetrics.getBlkIOServiceCount();
180             event.dataTransferred = containerMetrics.getBlkIOServiced();
181             event.commit();
182         }
183     }
184 
185     private static void emitContainerCPUThrottling() {
186         if (containerMetrics != null) {
187             ContainerCPUThrottlingEvent event = new ContainerCPUThrottlingEvent();
188 
189             event.cpuElapsedSlices = containerMetrics.getCpuNumPeriods();
190             event.cpuThrottledSlices = containerMetrics.getCpuNumThrottled();
191             event.cpuThrottledTime = containerMetrics.getCpuThrottledTime();
192             event.commit();
193         }
194     }
195 
196     public static void remove() {
197         PeriodicEvents.removeEvent(emitExceptionStatistics);
198         PeriodicEvents.removeEvent(emitDirectBufferStatistics);
199         PeriodicEvents.removeEvent(emitInitialSecurityProperties);
200 
201         PeriodicEvents.removeEvent(emitContainerConfiguration);
202         PeriodicEvents.removeEvent(emitContainerCPUUsage);
203         PeriodicEvents.removeEvent(emitContainerCPUThrottling);
204         PeriodicEvents.removeEvent(emitContainerMemoryUsage);
205         PeriodicEvents.removeEvent(emitContainerIOUsage);
206     }
207 
208     private static void emitDirectBufferStatistics() {
209         DirectBufferStatisticsEvent e = new DirectBufferStatisticsEvent();
210         e.commit();
211     }
212 
213     private static void emitInitialSecurityProperties() {
214         Properties p = SharedSecrets.getJavaSecurityPropertiesAccess().getInitialProperties();
215         if (p != null) {
216             for (String key : p.stringPropertyNames()) {
217                 InitialSecurityPropertyEvent e = new InitialSecurityPropertyEvent();
218                 e.key = key;
219                 e.value = p.getProperty(key);
220                 e.commit();
221             }
222         }
223     }
224 }