/* * Copyright (c) 2016, 2022, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions.
*/
/** * Provides means to configure, start, stop and dump recording data to disk. * <p> * The following example shows how configure, start, stop and dump recording data to disk. * * {@snippet class="Snippets" region="RecordingOverview"} * * @since 9
*/ publicfinalclass Recording implements Closeable {
@Override public Map<String, String> toMap() { return recording.getSettings();
}
}
privatefinal PlatformRecording internal;
/** * Creates a recording with settings from a map of name-value pairs. * <p> * A newly created recording is in the {@link RecordingState#NEW} state. To start * the recording, invoke the {@link Recording#start()} method. * * @param settings settings as a map of name-value pairs, not {@code null} * * @throws IllegalStateException if Flight Recorder can't be created (for * example, if the Java Virtual Machine (JVM) lacks Flight Recorder * support, or if the file repository can't be created or accessed) * * @throws SecurityException If a security manager is used and * FlightRecorderPermission "accessFlightRecorder" is not set. * * @see jdk.jfr
*/ public Recording(Map<String, String> settings) {
Objects.requireNonNull(settings, "settings");
Map<String, String> sanitized = Utils.sanitizeNullFreeStringMap(settings);
PlatformRecorder r = FlightRecorder.getFlightRecorder().getInternal(); synchronized (r) { this.internal = r.newRecording(sanitized); this.internal.setRecording(this); if (internal.getRecording() != this) { thrownew InternalError("Internal recording not properly setup");
}
}
}
/** * Creates a recording without any settings. * <p> * A newly created recording is in the {@link RecordingState#NEW} state. To start * the recording, invoke the {@link Recording#start()} method. * * @throws IllegalStateException if Flight Recorder can't be created (for * example, if the Java Virtual Machine (JVM) lacks Flight Recorder * support, or if the file repository can't be created or accessed) * * @throws SecurityException If a security manager is used and * FlightRecorderPermission "accessFlightRecorder" is not set.
*/ public Recording() { this(Map.of());
}
/** * Creates a recording with settings from a configuration. * <p> * The following example shows how create a recording that uses a predefined configuration. * * {@snippet : * Recording r = new Recording(Configuration.getConfiguration("default")); * } * * The newly created recording is in the {@link RecordingState#NEW} state. To * start the recording, invoke the {@link Recording#start()} method. * * @param configuration configuration that contains the settings to be use, not * {@code null} * * @throws IllegalStateException if Flight Recorder can't be created (for * example, if the Java Virtual Machine (JVM) lacks Flight Recorder * support, or if the file repository can't be created or accessed) * * @throws SecurityException if a security manager is used and * FlightRecorderPermission "accessFlightRecorder" is not set. * * @see Configuration
*/ public Recording(Configuration configuration) { this(Objects.requireNonNull(configuration, "configuration").getSettings());
}
/** * Starts this recording. * <p> * It's recommended that the recording options and event settings are configured * before calling this method. The benefits of doing so are a more consistent * state when analyzing the recorded data, and improved performance because the * configuration can be applied atomically. * <p> * After a successful invocation of this method, this recording is in the * {@code RUNNING} state. * * @throws IllegalStateException if recording is already started or is in the * {@code CLOSED} state
*/ publicvoid start() {
internal.start();
}
/** * Starts this recording after a delay. * <p> * After a successful invocation of this method, this recording is in the * {@code DELAYED} state. * * @param delay the time to wait before starting this recording, not * {@code null} * @throws IllegalStateException if the recording is not it the {@code NEW} state
*/ publicvoid scheduleStart(Duration delay) {
Objects.requireNonNull(delay, "delay");
internal.scheduleStart(delay);
}
/** * Stops this recording. * <p> * When a recording is stopped it can't be restarted. If this * recording has a destination, data is written to that destination and * the recording is closed. After a recording is closed, the data is no longer * available. * <p> * After a successful invocation of this method, this recording will be * in the {@code STOPPED} state. * * @return {@code true} if recording is stopped, {@code false} otherwise * * @throws IllegalStateException if the recording is not started or is already stopped * * @throws SecurityException if a security manager exists and the caller * doesn't have {@code FilePermission} to write to the destination * path * * @see #setDestination(Path) *
*/ publicboolean stop() { return internal.stop("Stopped by user");
}
/** * Returns settings used by this recording. * <p> * Modifying the returned {@code Map} will not change the settings for this recording. * <p> * If no settings are set for this recording, an empty {@code Map} is * returned. * * @return recording settings, not {@code null}
*/ public Map<String, String> getSettings() { returnnew HashMap<>(internal.getSettings());
}
/** * Returns the current size of this recording in the disk repository, * measured in bytes. * <p> * The size is updated when recording buffers are flushed. If the recording is * not written to the disk repository the returned size is always {@code 0}. * * @return amount of recorded data, measured in bytes, or {@code 0} if the * recording is not written to the disk repository
*/ publiclong getSize() { return internal.getSize();
}
/** * Returns the time when this recording was stopped. * * @return the time, or {@code null} if this recording is not stopped
*/ public Instant getStopTime() { return internal.getStopTime();
}
/** * Returns the time when this recording was started. * * @return the time, or {@code null} if this recording is not started
*/ public Instant getStartTime() { return internal.getStartTime();
}
/** * Returns the maximum size, measured in bytes, at which data is no longer kept in the disk repository. * * @return maximum size in bytes, or {@code 0} if no maximum size is set
*/ publiclong getMaxSize() { return internal.getMaxSize();
}
/** * Returns the length of time that the data is kept in the disk repository * before it is removed. * * @return maximum length of time, or {@code null} if no maximum length of time * has been set
*/ public Duration getMaxAge() { return internal.getMaxAge();
}
/** * Returns the name of this recording. * <p> * By default, the name is the same as the recording ID. * * @return the recording name, not {@code null}
*/ public String getName() { return internal.getName();
}
/** * Replaces all settings for this recording. * <p> * The following example shows how to set event settings for a recording. * * {@snippet : * Map<String, String> settings = new HashMap<>(); * settings.putAll(EventSettings.enabled("jdk.CPUSample").withPeriod(Duration.ofSeconds(2)).toMap()); * settings.putAll(EventSettings.enabled(MyEvent.class).withThreshold(Duration.ofSeconds(2)).withoutStackTrace().toMap()); * settings.put("jdk.ExecutionSample#period", "10 ms"); * recording.setSettings(settings); * } * * The following example shows how to merge settings. * * {@snippet : * Map<String, String> settings = recording.getSettings(); * settings.putAll(additionalSettings); * recording.setSettings(settings); * } * * @param settings the settings to set, not {@code null}
*/ publicvoid setSettings(Map<String, String> settings) {
Objects.requireNonNull(settings, "settings");
Map<String, String> sanitized = Utils.sanitizeNullFreeStringMap(settings);
internal.setSettings(sanitized);
}
/** * Returns the recording state that this recording is currently in. * * @return the recording state, not {@code null} * * @see RecordingState
*/ public RecordingState getState() { return internal.getState();
}
/** * Releases all data that is associated with this recording. * <p> * After a successful invocation of this method, this recording is in the * {@code CLOSED} state.
*/
@Override publicvoid close() {
internal.close();
}
/** * Returns a clone of this recording, with a new recording ID and name. * <p> * Clones are useful for dumping data without stopping the recording. After * a clone is created, the amount of data to copy is constrained * with the {@link #setMaxAge(Duration)} method and the {@link #setMaxSize(long)}method. * * @param stop {@code true} if the newly created copy should be stopped * immediately, {@code false} otherwise * @return the recording copy, not {@code null}
*/ public Recording copy(boolean stop) { return internal.newCopy(stop);
}
/** * Writes recording data to a file. * <p> * For a dump to succeed, the recording must either be 1) running, or 2) stopped * and to disk. If the recording is in any other state, an * {@link IOException} is thrown. * * @param destination the location where recording data is written, not * {@code null} * * @throws IOException if recording data can't be copied to the specified * location, for example, if the recording is closed or the * destination path is not writable * * @throws SecurityException if a security manager exists and the caller doesn't * have {@code FilePermission} to write to the destination path * * @see #getState() * @see #isToDisk()
*/ publicvoid dump(Path destination) throws IOException {
Objects.requireNonNull(destination, "destination");
internal.dump(new WriteableUserPath(destination));
}
/** * Returns {@code true} if this recording uses the disk repository, {@code false} otherwise. * <p> * If no value is set, {@code true} is returned. * * @return {@code true} if the recording uses the disk repository, {@code false} * otherwise
*/ publicboolean isToDisk() { return internal.isToDisk();
}
/** * Determines how much data is kept in the disk repository. * <p> * To control the amount of recording data that is stored on disk, the maximum * amount of data to retain can be specified. When the maximum limit is * exceeded, the Java Virtual Machine (JVM) removes the oldest chunk to make * room for a more recent chunk. * <p> * If neither maximum limit or the maximum age is set, the size of the * recording may grow indefinitely. * * @param maxSize the amount of data to retain, {@code 0} if infinite * * @throws IllegalArgumentException if {@code maxSize} is negative * * @throws IllegalStateException if the recording is in {@code CLOSED} state
*/ publicvoid setMaxSize(long maxSize) { if (maxSize < 0) { thrownew IllegalArgumentException("Max size of recording can't be negative");
}
internal.setMaxSize(maxSize);
}
/** * Returns how often events are made available for streaming purposes. * * @return the flush interval, or {@code null} if no interval has been set * * @since 14
*/ /*package private*/ Duration getFlushInterval() { return internal.getFlushInterval();
}
/** * Determines how far back data is kept in the disk repository. * <p> * To control the amount of recording data stored on disk, the maximum length of * time to retain the data can be specified. Data stored on disk that is older * than the specified length of time is removed by the Java Virtual Machine (JVM). * <p> * If neither maximum limit or the maximum age is set, the size of the * recording may grow indefinitely. * * @param maxAge the length of time that data is kept, or {@code null} if infinite * * @throws IllegalArgumentException if {@code maxAge} is negative * * @throws IllegalStateException if the recording is in the {@code CLOSED} state
*/ publicvoid setMaxAge(Duration maxAge) { if (maxAge != null && maxAge.isNegative()) { thrownew IllegalArgumentException("Max age of recording can't be negative");
}
internal.setMaxAge(maxAge);
}
/** * Sets a location where data is written on recording stop, or * {@code null} if data is not to be dumped. * <p> * If a destination is set, this recording is automatically closed * after data is successfully copied to the destination path. * <p> * If a destination is <em>not</em> set, Flight Recorder retains the * recording data until this recording is closed. Use the {@link #dump(Path)} method to * manually write data to a file. * * @param destination the destination path, or {@code null} if recording should * not be dumped at stop * * @throws IllegalStateException if recording is in the {@code STOPPED} or * {@code CLOSED} state. * * @throws SecurityException if a security manager exists and the caller * doesn't have {@code FilePermission} to read, write, and delete the * {@code destination} file * * @throws IOException if the path is not writable
*/ publicvoid setDestination(Path destination) throws IOException {
internal.setDestination(destination != null ? new WriteableUserPath(destination) : null);
}
/** * Returns the destination file, where recording data is written when the * recording stops, or {@code null} if no destination is set. * * @return the destination file, or {@code null} if not set.
*/ public Path getDestination() {
WriteableUserPath usp = internal.getDestination(); if (usp == null) { returnnull;
} else { return usp.getPotentiallyMaliciousOriginal();
}
}
/** * Returns a unique ID for this recording. * * @return the recording ID
*/ publiclong getId() { return internal.getId();
}
/** * Sets a human-readable name (for example, {@code "My Recording"}). * * @param name the recording name, not {@code null} * * @throws IllegalStateException if the recording is in {@code CLOSED} state
*/ publicvoid setName(String name) {
Objects.requireNonNull(name, "name");
internal.setName(name);
}
/** * Sets whether this recording is dumped to disk when the JVM exits. * * @param dumpOnExit if this recording should be dumped when the JVM exits
*/ publicvoid setDumpOnExit(boolean dumpOnExit) {
internal.setDumpOnExit(dumpOnExit);
}
/** * Returns whether this recording is dumped to disk when the JVM exits. * <p> * If dump on exit is not set, {@code false} is returned. * * @return {@code true} if the recording is dumped on exit, {@code false} * otherwise.
*/ publicboolean getDumpOnExit() { return internal.getDumpOnExit();
}
/** * Determines whether this recording is continuously flushed to the disk * repository or data is constrained to what is available in memory buffers. * * @param disk {@code true} if this recording is written to disk, * {@code false} if in-memory *
*/ publicvoid setToDisk(boolean disk) {
internal.setToDisk(disk);
}
/** * Creates a data stream for a specified interval. * <p> * The stream may contain some data outside the specified range. * <p> * If the recording is not to disk, a stream can't be created * and {@code null} is returned. * * @param start the start time for the stream, or {@code null} to get data from * start time of the recording * * @param end the end time for the stream, or {@code null} to get data until the * present time. * * @return an input stream, or {@code null} if no data is available in the * interval, or the recording was not recorded to disk * * @throws IllegalArgumentException if {@code end} happens before * {@code start} * * @throws IOException if a stream can't be opened * * @see #setToDisk(boolean)
*/ public InputStream getStream(Instant start, Instant end) throws IOException { if (start != null && end != null && end.isBefore(start)) { thrownew IllegalArgumentException("End time of requested stream must not be before start time");
} return internal.open(start, end);
}
/** * Returns the specified duration for this recording, or {@code null} if no * duration is set. * <p> * The duration can be set only when the recording is in the * {@link RecordingState#NEW} state. * * @return the desired duration of the recording, or {@code null} if no duration * has been set.
*/ public Duration getDuration() { return internal.getDuration();
}
/** * Sets a duration for how long a recording runs before it stops. * <p> * By default, a recording has no duration ({@code null}). * * @param duration the duration, or {@code null} if no duration is set * * @throws IllegalStateException if recording is in the {@code STOPPED} or {@code CLOSED} state
*/ publicvoid setDuration(Duration duration) {
internal.setDuration(duration);
}
/** * Enables the event with the specified name. * <p> * If multiple events have the same name (for example, the same class is loaded * in different class loaders), then all events that match the name are enabled. To * enable a specific class, use the {@link #enable(Class)} method or a {@code String} * representation of the event type ID. * * @param name the settings for the event, not {@code null} * * @return an event setting for further configuration, not {@code null} * * @see EventType
*/ public EventSettings enable(String name) {
Objects.requireNonNull(name, "name");
RecordingSettings rs = new RecordingSettings(this, name);
rs.with("enabled", "true"); return rs;
}
/** * Disables event with the specified name. * <p> * If multiple events with same name (for example, the same class is loaded * in different class loaders), then all events that match the * name is disabled. To disable a specific class, use the * {@link #disable(Class)} method or a {@code String} representation of the event * type ID. * * @param name the settings for the event, not {@code null} * * @return an event setting for further configuration, not {@code null} *
*/ public EventSettings disable(String name) {
Objects.requireNonNull(name, "name");
RecordingSettings rs = new RecordingSettings(this, name);
rs.with("enabled", "false"); return rs;
}
/** * Enables event. * * @param eventClass the event to enable, not {@code null} * * @throws IllegalArgumentException if {@code eventClass} is an abstract * class or not a subclass of {@link Event} * * @return an event setting for further configuration, not {@code null}
*/ public EventSettings enable(Class<? extends Event> eventClass) {
Objects.requireNonNull(eventClass, "eventClass");
RecordingSettings rs = new RecordingSettings(this, eventClass);
rs.with("enabled", "true"); return rs;
}
/** * Disables event. * * @param eventClass the event to enable, not {@code null} * * @throws IllegalArgumentException if {@code eventClass} is an abstract * class or not a subclass of {@link Event} * * @return an event setting for further configuration, not {@code null} *
*/ public EventSettings disable(Class<? extends Event> eventClass) {
Objects.requireNonNull(eventClass, "eventClass");
RecordingSettings rs = new RecordingSettings(this, eventClass);
rs.with("enabled", "false"); return rs;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.