src/jdk.jfr/share/classes/jdk/jfr/consumer/RecordingStream.java
changeset 58863 c16ac7a2eba4
child 59226 a0f39cc47387
equal deleted inserted replaced
58861:2c3cc4b01880 58863:c16ac7a2eba4
       
     1 /*
       
     2  * Copyright (c) 2019, 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.consumer;
       
    27 
       
    28 import java.io.IOException;
       
    29 import java.security.AccessControlContext;
       
    30 import java.security.AccessController;
       
    31 import java.time.Duration;
       
    32 import java.time.Instant;
       
    33 import java.util.Map;
       
    34 import java.util.function.Consumer;
       
    35 
       
    36 import jdk.jfr.Configuration;
       
    37 import jdk.jfr.Event;
       
    38 import jdk.jfr.EventSettings;
       
    39 import jdk.jfr.EventType;
       
    40 import jdk.jfr.Recording;
       
    41 import jdk.jfr.internal.PlatformRecording;
       
    42 import jdk.jfr.internal.PrivateAccess;
       
    43 import jdk.jfr.internal.SecuritySupport;
       
    44 import jdk.jfr.internal.Utils;
       
    45 import jdk.jfr.internal.consumer.EventDirectoryStream;
       
    46 
       
    47 /**
       
    48  * A recording stream produces events from the current JVM (Java Virtual
       
    49  * Machine).
       
    50  * <p>
       
    51  * The following example shows how to record events using the default
       
    52  * configuration and print the Garbage Collection, CPU Load and JVM Information
       
    53  * event to standard out.
       
    54  * <pre>
       
    55  * <code>
       
    56  * Configuration c = Configuration.getConfiguration("default");
       
    57  * try (var rs = new RecordingStream(c)) {
       
    58  *     rs.onEvent("jdk.GarbageCollection", System.out::println);
       
    59  *     rs.onEvent("jdk.CPULoad", System.out::println);
       
    60  *     rs.onEvent("jdk.JVMInformation", System.out::println);
       
    61  *     rs.start();
       
    62  *   }
       
    63  * }
       
    64  * </code>
       
    65  * </pre>
       
    66  *
       
    67  * @since 14
       
    68  */
       
    69 public final class RecordingStream implements AutoCloseable, EventStream {
       
    70 
       
    71     private final Recording recording;
       
    72     private final EventDirectoryStream directoryStream;
       
    73 
       
    74     /**
       
    75      * Creates an event stream for the current JVM (Java Virtual Machine).
       
    76      *
       
    77      * @throws IllegalStateException if Flight Recorder can't be created (for
       
    78      *         example, if the Java Virtual Machine (JVM) lacks Flight Recorder
       
    79      *         support, or if the file repository can't be created or accessed)
       
    80      *
       
    81      * @throws SecurityException if a security manager exists and the caller
       
    82      *         does not have
       
    83      *         {@code FlightRecorderPermission("accessFlightRecorder")}
       
    84      */
       
    85     public RecordingStream() {
       
    86         Utils.checkAccessFlightRecorder();
       
    87         AccessControlContext acc = AccessController.getContext();
       
    88         this.recording = new Recording();
       
    89         this.recording.setFlushInterval(Duration.ofMillis(1000));
       
    90         try {
       
    91             this.directoryStream = new EventDirectoryStream(acc, null, SecuritySupport.PRIVILIGED, true);
       
    92         } catch (IOException ioe) {
       
    93             this.recording.close();
       
    94             throw new IllegalStateException(ioe.getMessage());
       
    95         }
       
    96     }
       
    97 
       
    98     /**
       
    99      * Creates a recording stream using settings from a configuration.
       
   100      * <p>
       
   101      * The following example shows how to create a recording stream that uses a
       
   102      * predefined configuration.
       
   103      *
       
   104      * <pre>
       
   105      * <code>
       
   106      * var c = Configuration.getConfiguration("default");
       
   107      * try (var rs = new RecordingStream(c)) {
       
   108      *   rs.onEvent(System.out::println);
       
   109      *   rs.start();
       
   110      * }
       
   111      * </code>
       
   112      * </pre>
       
   113      *
       
   114      * @param configuration configuration that contains the settings to use,
       
   115      *        not {@code null}
       
   116      *
       
   117      * @throws IllegalStateException if Flight Recorder can't be created (for
       
   118      *         example, if the Java Virtual Machine (JVM) lacks Flight Recorder
       
   119      *         support, or if the file repository can't be created or accessed)
       
   120      *
       
   121      * @throws SecurityException if a security manager is used and
       
   122      *         FlightRecorderPermission "accessFlightRecorder" is not set.
       
   123      *
       
   124      * @see Configuration
       
   125      */
       
   126     public RecordingStream(Configuration configuration) {
       
   127         this();
       
   128         recording.setSettings(configuration.getSettings());
       
   129     }
       
   130 
       
   131     /**
       
   132      * Enables the event with the specified name.
       
   133      * <p>
       
   134      * If multiple events have the same name (for example, the same class is
       
   135      * loaded in different class loaders), then all events that match the name
       
   136      * are enabled. To enable a specific class, use the {@link #enable(Class)}
       
   137      * method or a {@code String} representation of the event type ID.
       
   138      *
       
   139      * @param name the settings for the event, not {@code null}
       
   140      *
       
   141      * @return an event setting for further configuration, not {@code null}
       
   142      *
       
   143      * @see EventType
       
   144      */
       
   145     public EventSettings enable(String name) {
       
   146         return recording.enable(name);
       
   147     }
       
   148 
       
   149     /**
       
   150      * Replaces all settings for this recording stream.
       
   151      * <p>
       
   152      * The following example records 20 seconds using the "default" configuration
       
   153      * and then changes settings to the "profile" configuration.
       
   154      *
       
   155      * <pre>
       
   156      * <code>
       
   157      *     Configuration defaultConfiguration = Configuration.getConfiguration("default");
       
   158      *     Configuration profileConfiguration = Configuration.getConfiguration("profile");
       
   159      *     try (var rs = new RecordingStream(defaultConfiguration) {
       
   160      *        rs.onEvent(System.out::println);
       
   161      *        rs.startAsync();
       
   162      *        Thread.sleep(20_000);
       
   163      *        rs.setSettings(profileConfiguration.getSettings());
       
   164      *        Thread.sleep(20_000);
       
   165      *     }
       
   166      * </code>
       
   167      * </pre>
       
   168      *
       
   169      * @param settings the settings to set, not {@code null}
       
   170      *
       
   171      * @see Recording#setSettings(Map)
       
   172      */
       
   173     public void setSettings(Map<String, String> settings) {
       
   174         recording.setSettings(settings);
       
   175     };
       
   176 
       
   177     /**
       
   178      * Enables event.
       
   179      *
       
   180      * @param eventClass the event to enable, not {@code null}
       
   181      *
       
   182      * @throws IllegalArgumentException if {@code eventClass} is an abstract
       
   183      *         class or not a subclass of {@link Event}
       
   184      *
       
   185      * @return an event setting for further configuration, not {@code null}
       
   186      */
       
   187     public EventSettings enable(Class<? extends Event> eventClass) {
       
   188         return recording.enable(eventClass);
       
   189     }
       
   190 
       
   191     /**
       
   192      * Disables event with the specified name.
       
   193      * <p>
       
   194      * If multiple events with same name (for example, the same class is loaded
       
   195      * in different class loaders), then all events that match the name are
       
   196      * disabled. To disable a specific class, use the {@link #disable(Class)}
       
   197      * method or a {@code String} representation of the event type ID.
       
   198      *
       
   199      * @param name the settings for the event, not {@code null}
       
   200      *
       
   201      * @return an event setting for further configuration, not {@code null}
       
   202      *
       
   203      */
       
   204     public EventSettings disable(String name) {
       
   205         return recording.disable(name);
       
   206     }
       
   207 
       
   208     /**
       
   209      * Disables event.
       
   210      *
       
   211      * @param eventClass the event to enable, not {@code null}
       
   212      *
       
   213      * @throws IllegalArgumentException if {@code eventClass} is an abstract
       
   214      *         class or not a subclass of {@link Event}
       
   215      *
       
   216      * @return an event setting for further configuration, not {@code null}
       
   217      *
       
   218      */
       
   219     public EventSettings disable(Class<? extends Event> eventClass) {
       
   220         return recording.disable(eventClass);
       
   221     }
       
   222 
       
   223     /**
       
   224      * Determines how far back data is kept for the stream.
       
   225      * <p>
       
   226      * To control the amount of recording data stored on disk, the maximum
       
   227      * length of time to retain the data can be specified. Data stored on disk
       
   228      * that is older than the specified length of time is removed by the Java
       
   229      * Virtual Machine (JVM).
       
   230      * <p>
       
   231      * If neither maximum limit or the maximum age is set, the size of the
       
   232      * recording may grow indefinitely if events are on
       
   233      *
       
   234      * @param maxAge the length of time that data is kept, or {@code null} if
       
   235      *        infinite
       
   236      *
       
   237      * @throws IllegalArgumentException if {@code maxAge} is negative
       
   238      *
       
   239      * @throws IllegalStateException if the recording is in the {@code CLOSED}
       
   240      *         state
       
   241      */
       
   242     public void setMaxAge(Duration maxAge) {
       
   243         recording.setMaxAge(maxAge);
       
   244     }
       
   245 
       
   246     /**
       
   247      * Determines how much data is kept for the stream.
       
   248      * <p>
       
   249      * To control the amount of recording data that is stored on disk, the
       
   250      * maximum amount of data to retain can be specified. When the maximum limit
       
   251      * is exceeded, the Java Virtual Machine (JVM) removes the oldest chunk to
       
   252      * make room for a more recent chunk.
       
   253      * <p>
       
   254      * If neither maximum limit or the maximum age is set, the size of the
       
   255      * recording may grow indefinitely.
       
   256      * <p>
       
   257      * The size is measured in bytes.
       
   258      *
       
   259      * @param maxSize the amount of data to retain, {@code 0} if infinite
       
   260      *
       
   261      * @throws IllegalArgumentException if {@code maxSize} is negative
       
   262      *
       
   263      * @throws IllegalStateException if the recording is in {@code CLOSED} state
       
   264      */
       
   265     public void setMaxSize(long maxSize) {
       
   266         recording.setMaxSize(maxSize);
       
   267     }
       
   268 
       
   269     /**
       
   270      * Determines how often events are made available for streaming.
       
   271      *
       
   272      * @param interval the interval at which events are made available to the
       
   273      *        stream, no {@code null}
       
   274      *
       
   275      * @throws IllegalArgumentException if {@code interval} is negative
       
   276      *
       
   277      * @throws IllegalStateException if the stream is closed
       
   278      */
       
   279     public void setFlushInterval(Duration interval) {
       
   280         recording.setFlushInterval(interval);
       
   281     }
       
   282 
       
   283     @Override
       
   284     public void setReuse(boolean reuse) {
       
   285         directoryStream.setReuse(reuse);
       
   286     }
       
   287 
       
   288     @Override
       
   289     public void setOrdered(boolean ordered) {
       
   290         directoryStream.setOrdered(ordered);
       
   291     }
       
   292 
       
   293     @Override
       
   294     public void setStartTime(Instant startTime) {
       
   295         directoryStream.setStartTime(startTime);
       
   296     }
       
   297 
       
   298     @Override
       
   299     public void setEndTime(Instant endTime) {
       
   300         directoryStream.setEndTime(endTime);
       
   301     }
       
   302 
       
   303     @Override
       
   304     public void onEvent(String eventName, Consumer<RecordedEvent> action) {
       
   305         directoryStream.onEvent(eventName, action);
       
   306     }
       
   307 
       
   308     @Override
       
   309     public void onEvent(Consumer<RecordedEvent> action) {
       
   310         directoryStream.onEvent(action);
       
   311     }
       
   312 
       
   313     @Override
       
   314     public void onFlush(Runnable action) {
       
   315         directoryStream.onFlush(action);
       
   316     }
       
   317 
       
   318     @Override
       
   319     public void onClose(Runnable action) {
       
   320         directoryStream.onClose(action);
       
   321     }
       
   322 
       
   323     @Override
       
   324     public void onError(Consumer<Throwable> action) {
       
   325         directoryStream.onError(action);
       
   326     }
       
   327 
       
   328     @Override
       
   329     public void close() {
       
   330         recording.close();
       
   331         directoryStream.close();
       
   332     }
       
   333 
       
   334     @Override
       
   335     public boolean remove(Object action) {
       
   336         return directoryStream.remove(action);
       
   337     }
       
   338 
       
   339     @Override
       
   340     public void start() {
       
   341         PlatformRecording pr = PrivateAccess.getInstance().getPlatformRecording(recording);
       
   342         long startNanos = pr.start();
       
   343         directoryStream.start(startNanos);
       
   344     }
       
   345 
       
   346     @Override
       
   347     public void startAsync() {
       
   348         PlatformRecording pr = PrivateAccess.getInstance().getPlatformRecording(recording);
       
   349         long startNanos = pr.start();
       
   350         directoryStream.startAsync(startNanos);
       
   351     }
       
   352 
       
   353     @Override
       
   354     public void awaitTermination(Duration timeout) throws InterruptedException {
       
   355         directoryStream.awaitTermination(timeout);
       
   356     }
       
   357 
       
   358     @Override
       
   359     public void awaitTermination() throws InterruptedException {
       
   360         directoryStream.awaitTermination();
       
   361     }
       
   362 }