src/jdk.jfr/share/classes/jdk/jfr/consumer/RecordingStream.java
branchJEP-349-branch
changeset 57361 53dccc90a5be
child 57376 8e8a06a3059c
equal deleted inserted replaced
57360:5d043a159d5c 57361:53dccc90a5be
       
     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.util.function.Consumer;
       
    33 
       
    34 import jdk.jfr.Configuration;
       
    35 import jdk.jfr.Event;
       
    36 import jdk.jfr.EventSettings;
       
    37 import jdk.jfr.EventType;
       
    38 import jdk.jfr.Recording;
       
    39 import jdk.jfr.internal.PlatformRecording;
       
    40 import jdk.jfr.internal.PrivateAccess;
       
    41 import jdk.jfr.internal.Utils;
       
    42 
       
    43 /**
       
    44  * An event stream produces events from a file, directory or a running JVM (Java
       
    45  * Virtual Machine).
       
    46  */
       
    47 public class RecordingStream implements AutoCloseable, EventStream {
       
    48 
       
    49     private final Recording recording;
       
    50     private final EventDirectoryStream stream;
       
    51 
       
    52     /**
       
    53      * Creates an event stream for this JVM (Java Virtual Machine).
       
    54      * <p>
       
    55      * The following example shows how to create a recording stream that prints
       
    56      * CPU usage and information about garbage collections.
       
    57      *
       
    58      * <pre>
       
    59      * <code>
       
    60      * try (RecordingStream  r = new RecordingStream()) {
       
    61      *   r.enable("jdk.GarbageCollection");
       
    62      *   r.enable("jdk.CPULoad").withPeriod(Duration.ofSeconds(1));
       
    63      *   r.onEvent(System.out::println);
       
    64      *   r.start();
       
    65      * }
       
    66      * </code>
       
    67      * </pre>
       
    68      *
       
    69      * @throws IllegalStateException if Flight Recorder can't be created (for
       
    70      *         example, if the Java Virtual Machine (JVM) lacks Flight Recorder
       
    71      *         support, or if the file repository can't be created or accessed)
       
    72      *
       
    73      * @throws SecurityException if a security manager exists and the caller
       
    74      *         does not have
       
    75      *         {@code FlightRecorderPermission("accessFlightRecorder")}
       
    76      */
       
    77     public RecordingStream() {
       
    78         Utils.checkAccessFlightRecorder();
       
    79         AccessControlContext acc = AccessController.getContext();
       
    80         this.recording = new Recording();
       
    81         this.recording.setFlushInterval(Duration.ofMillis(1000));
       
    82         try {
       
    83             this.stream = new EventDirectoryStream(acc);
       
    84         } catch (IOException ioe) {
       
    85             throw new IllegalStateException(ioe.getMessage());
       
    86         }
       
    87     }
       
    88 
       
    89     /**
       
    90      * Creates a recording stream using settings from a configuration.
       
    91      * <p>
       
    92      * The following example shows how to create a recording stream that uses a
       
    93      * predefined configuration.
       
    94      *
       
    95      * <pre>
       
    96      * <code>
       
    97      * Configuration c = Configuration.getConfiguration("default");
       
    98      * try (RecordingStream  r = new RecordingStream(c)) {
       
    99      *   r.onEvent(System.out::println);
       
   100      *   r.start();
       
   101      * }
       
   102      * </code>
       
   103      * </pre>
       
   104      *
       
   105      * @param configuration configuration that contains the settings to be use,
       
   106      *        not {@code null}
       
   107      *
       
   108      * @throws IllegalStateException if Flight Recorder can't be created (for
       
   109      *         example, if the Java Virtual Machine (JVM) lacks Flight Recorder
       
   110      *         support, or if the file repository can't be created or accessed)
       
   111      *
       
   112      * @throws SecurityException if a security manager is used and
       
   113      *         FlightRecorderPermission "accessFlightRecorder" is not set.
       
   114      *
       
   115      * @see Configuration
       
   116      */
       
   117     public RecordingStream(Configuration configuration) {
       
   118         this();
       
   119         recording.setSettings(configuration.getSettings());
       
   120     }
       
   121 
       
   122     /**
       
   123      * Enables the event with the specified name.
       
   124      * <p>
       
   125      * If multiple events have the same name (for example, the same class is
       
   126      * loaded in different class loaders), then all events that match the name
       
   127      * are enabled. To enable a specific class, use the {@link #enable(Class)}
       
   128      * method or a {@code String} representation of the event type ID.
       
   129      *
       
   130      * @param name the settings for the event, not {@code null}
       
   131      *
       
   132      * @return an event setting for further configuration, not {@code null}
       
   133      *
       
   134      * @see EventType
       
   135      */
       
   136     public EventSettings enable(String name) {
       
   137         return recording.enable(name);
       
   138     }
       
   139 
       
   140     /**
       
   141      * Enables event.
       
   142      *
       
   143      * @param eventClass the event to enable, not {@code null}
       
   144      *
       
   145      * @throws IllegalArgumentException if {@code eventClass} is an abstract
       
   146      *         class or not a subclass of {@link Event}
       
   147      *
       
   148      * @return an event setting for further configuration, not {@code null}
       
   149      */
       
   150     public EventSettings enable(Class<? extends Event> eventClass) {
       
   151         return recording.enable(eventClass);
       
   152     }
       
   153 
       
   154     /**
       
   155      * Disables event with the specified name.
       
   156      * <p>
       
   157      * If multiple events with same name (for example, the same class is loaded
       
   158      * in different class loaders), then all events that match the name is
       
   159      * disabled. To disable a specific class, use the {@link #disable(Class)}
       
   160      * method or a {@code String} representation of the event type ID.
       
   161      *
       
   162      * @param name the settings for the event, not {@code null}
       
   163      *
       
   164      * @return an event setting for further configuration, not {@code null}
       
   165      *
       
   166      */
       
   167     public EventSettings disable(String name) {
       
   168         return recording.disable(name);
       
   169     }
       
   170 
       
   171     /**
       
   172      * Disables event.
       
   173      *
       
   174      * @param eventClass the event to enable, not {@code null}
       
   175      *
       
   176      * @throws IllegalArgumentException if {@code eventClass} is an abstract
       
   177      *         class or not a subclass of {@link Event}
       
   178      *
       
   179      * @return an event setting for further configuration, not {@code null}
       
   180      *
       
   181      */
       
   182     public EventSettings disable(Class<? extends Event> eventClass) {
       
   183         return recording.disable(eventClass);
       
   184     }
       
   185     /**
       
   186      * Determines how far back data is kept for the stream if the stream can't
       
   187      * keep up.
       
   188      * <p>
       
   189      * To control the amount of recording data stored on disk, the maximum
       
   190      * length of time to retain the data can be specified. Data stored on disk
       
   191      * that is older than the specified length of time is removed by the Java
       
   192      * Virtual Machine (JVM).
       
   193      * <p>
       
   194      * If neither maximum limit or the maximum age is set, the size of the
       
   195      * recording may grow indefinitely if events are on
       
   196      *
       
   197      * @param maxAge the length of time that data is kept, or {@code null} if
       
   198      *        infinite
       
   199      *
       
   200      * @throws IllegalArgumentException if <code>maxAge</code> is negative
       
   201      *
       
   202      * @throws IllegalStateException if the recording is in the {@code CLOSED}
       
   203      *         state
       
   204      */
       
   205     public void setMaxAge(Duration maxAge) {
       
   206         recording.setMaxAge(maxAge);
       
   207     }
       
   208 
       
   209     /**
       
   210      * Determines how much data is kept in the disk repository if the stream
       
   211      * can't keep up.
       
   212      * <p>
       
   213      * To control the amount of recording data that is stored on disk, the
       
   214      * maximum amount of data to retain can be specified. When the maximum limit
       
   215      * is exceeded, the Java Virtual Machine (JVM) removes the oldest chunk to
       
   216      * make room for a more recent chunk.
       
   217      * <p>
       
   218      * If neither maximum limit or the maximum age is set, the size of the
       
   219      * recording may grow indefinitely.
       
   220      *
       
   221      * @param maxSize the amount of data to retain, {@code 0} if infinite
       
   222      *
       
   223      * @throws IllegalArgumentException if <code>maxSize</code> is negative
       
   224      *
       
   225      * @throws IllegalStateException if the recording is in {@code CLOSED} state
       
   226      */
       
   227     public void setMaxSize(long maxSize) {
       
   228         recording.setMaxSize(maxSize);
       
   229     }
       
   230 
       
   231     @Override
       
   232     public void onEvent(String eventName, Consumer<RecordedEvent> action) {
       
   233         stream.onEvent(eventName, action);
       
   234     }
       
   235 
       
   236     @Override
       
   237     public void onEvent(Consumer<RecordedEvent> action) {
       
   238         stream.onEvent(action);
       
   239     }
       
   240 
       
   241     @Override
       
   242     public void onFlush(Runnable action) {
       
   243         stream.onFlush(action);
       
   244     }
       
   245 
       
   246     @Override
       
   247     public void onClose(Runnable action) {
       
   248         stream.onClose(action);
       
   249     }
       
   250 
       
   251     @Override
       
   252     public void close() {
       
   253         recording.close();
       
   254         stream.close();
       
   255     }
       
   256 
       
   257     @Override
       
   258     public boolean remove(Object action) {
       
   259         return stream.remove(action);
       
   260     }
       
   261 
       
   262     @Override
       
   263     public void start() {
       
   264         PlatformRecording pr = PrivateAccess.getInstance().getPlatformRecording(recording);
       
   265         long startNanos = pr.start();
       
   266         stream.start(startNanos);
       
   267     }
       
   268 
       
   269     @Override
       
   270     public void startAsync() {
       
   271         PlatformRecording pr = PrivateAccess.getInstance().getPlatformRecording(recording);
       
   272         long startNanos = pr.start();
       
   273         stream.startAsync(startNanos);
       
   274     }
       
   275 
       
   276     @Override
       
   277     public void awaitTermination(Duration timeout) {
       
   278         stream.awaitTermination(timeout);
       
   279     }
       
   280 
       
   281     /**
       
   282      * Determines how often events are made available for streaming.
       
   283      *
       
   284      * @param interval the interval at which events are made available to the
       
   285      *        stream
       
   286      *
       
   287      * @throws IllegalArgumentException if <code>interval</code> is negative
       
   288      *
       
   289      * @throws IllegalStateException if the stream is closed
       
   290      */
       
   291     public void setInterval(Duration duration) {
       
   292         recording.setFlushInterval(duration);
       
   293     }
       
   294 
       
   295     @Override
       
   296     public void awaitTermination() {
       
   297         stream.awaitTermination();
       
   298     }
       
   299 }