author | mgronlun |
Wed, 30 Oct 2019 19:43:52 +0100 | |
changeset 58863 | c16ac7a2eba4 |
parent 53016 | 9f13f8aad8dc |
permissions | -rw-r--r-- |
50113 | 1 |
/* |
58863 | 2 |
* Copyright (c) 2016, 2019, Oracle and/or its affiliates. All rights reserved. |
50113 | 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; |
|
27 |
||
28 |
import java.io.Closeable; |
|
29 |
import java.io.IOException; |
|
30 |
import java.io.InputStream; |
|
31 |
import java.nio.file.Path; |
|
32 |
import java.time.Duration; |
|
33 |
import java.time.Instant; |
|
34 |
import java.util.HashMap; |
|
35 |
import java.util.Map; |
|
36 |
import java.util.Objects; |
|
37 |
||
50745 | 38 |
import jdk.jfr.internal.PlatformRecorder; |
50113 | 39 |
import jdk.jfr.internal.PlatformRecording; |
40 |
import jdk.jfr.internal.Type; |
|
41 |
import jdk.jfr.internal.Utils; |
|
42 |
import jdk.jfr.internal.WriteableUserPath; |
|
43 |
||
44 |
/** |
|
45 |
* Provides means to configure, start, stop and dump recording data to disk. |
|
46 |
* <p> |
|
47 |
* The following example shows how configure, start, stop and dump recording data to disk. |
|
48 |
* |
|
49 |
* <pre> |
|
50 |
* <code> |
|
51 |
* Configuration c = Configuration.getConfiguration("default"); |
|
52 |
* Recording r = new Recording(c); |
|
53 |
* r.start(); |
|
54 |
* System.gc(); |
|
55 |
* Thread.sleep(5000); |
|
56 |
* r.stop(); |
|
53016
9f13f8aad8dc
8215237: jdk.jfr.Recording javadoc does not compile
egahlin
parents:
50745
diff
changeset
|
57 |
* r.dump(Files.createTempFile("my-recording", ".jfr")); |
50113 | 58 |
* </code> |
59 |
* </pre> |
|
60 |
* |
|
61 |
* @since 9 |
|
62 |
*/ |
|
63 |
public final class Recording implements Closeable { |
|
64 |
||
65 |
private static class RecordingSettings extends EventSettings { |
|
66 |
||
67 |
private final Recording recording; |
|
68 |
private final String identifier; |
|
69 |
||
70 |
RecordingSettings(Recording r, String identifier) { |
|
71 |
this.recording = r; |
|
72 |
this.identifier = identifier; |
|
73 |
} |
|
74 |
||
75 |
RecordingSettings(Recording r, Class<? extends Event> eventClass) { |
|
76 |
Utils.ensureValidEventSubclass(eventClass); |
|
77 |
this.recording = r; |
|
78 |
this.identifier = String.valueOf(Type.getTypeId(eventClass)); |
|
79 |
} |
|
80 |
||
81 |
@Override |
|
82 |
public EventSettings with(String name, String value) { |
|
83 |
Objects.requireNonNull(value); |
|
84 |
recording.setSetting(identifier + "#" + name, value); |
|
85 |
return this; |
|
86 |
} |
|
87 |
||
88 |
@Override |
|
89 |
public Map<String, String> toMap() { |
|
90 |
return recording.getSettings(); |
|
91 |
} |
|
92 |
} |
|
93 |
||
94 |
private final PlatformRecording internal; |
|
95 |
||
50745 | 96 |
public Recording(Map<String, String> settings) { |
97 |
PlatformRecorder r = FlightRecorder.getFlightRecorder().getInternal(); |
|
98 |
synchronized (r) { |
|
99 |
this.internal = r.newRecording(settings); |
|
100 |
this.internal.setRecording(this); |
|
101 |
if (internal.getRecording() != this) { |
|
102 |
throw new InternalError("Internal recording not properly setup"); |
|
103 |
} |
|
50113 | 104 |
} |
105 |
} |
|
106 |
||
107 |
/** |
|
108 |
* Creates a recording without any settings. |
|
109 |
* <p> |
|
110 |
* A newly created recording is in the {@link RecordingState#NEW} state. To start |
|
111 |
* the recording, invoke the {@link Recording#start()} method. |
|
112 |
* |
|
113 |
* @throws IllegalStateException if Flight Recorder can't be created (for |
|
114 |
* example, if the Java Virtual Machine (JVM) lacks Flight Recorder |
|
115 |
* support, or if the file repository can't be created or accessed) |
|
116 |
* |
|
117 |
* @throws SecurityException If a security manager is used and |
|
118 |
* FlightRecorderPermission "accessFlightRecorder" is not set. |
|
119 |
*/ |
|
120 |
public Recording() { |
|
50745 | 121 |
this(new HashMap<String, String>()); |
122 |
} |
|
50113 | 123 |
|
124 |
/** |
|
125 |
* Creates a recording with settings from a configuration. |
|
126 |
* <p> |
|
127 |
* The following example shows how create a recording that uses a predefined configuration. |
|
128 |
* |
|
129 |
* <pre> |
|
130 |
* <code> |
|
131 |
* Recording r = new Recording(Configuration.getConfiguration("default")); |
|
132 |
* </code> |
|
133 |
* </pre> |
|
134 |
* |
|
135 |
* The newly created recording is in the {@link RecordingState#NEW} state. To |
|
136 |
* start the recording, invoke the {@link Recording#start()} method. |
|
137 |
* |
|
138 |
* @param configuration configuration that contains the settings to be use, not |
|
139 |
* {@code null} |
|
140 |
* |
|
141 |
* @throws IllegalStateException if Flight Recorder can't be created (for |
|
142 |
* example, if the Java Virtual Machine (JVM) lacks Flight Recorder |
|
143 |
* support, or if the file repository can't be created or accessed) |
|
144 |
* |
|
145 |
* @throws SecurityException if a security manager is used and |
|
146 |
* FlightRecorderPermission "accessFlightRecorder" is not set. |
|
147 |
* |
|
148 |
* @see Configuration |
|
149 |
*/ |
|
150 |
public Recording(Configuration configuration) { |
|
50745 | 151 |
this(configuration.getSettings()); |
50113 | 152 |
} |
153 |
||
154 |
/** |
|
155 |
* Starts this recording. |
|
156 |
* <p> |
|
157 |
* It's recommended that the recording options and event settings are configured |
|
158 |
* before calling this method. The benefits of doing so are a more consistent |
|
159 |
* state when analyzing the recorded data, and improved performance because the |
|
160 |
* configuration can be applied atomically. |
|
161 |
* <p> |
|
162 |
* After a successful invocation of this method, this recording is in the |
|
163 |
* {@code RUNNING} state. |
|
164 |
* |
|
165 |
* @throws IllegalStateException if recording is already started or is in the |
|
166 |
* {@code CLOSED} state |
|
167 |
*/ |
|
168 |
public void start() { |
|
169 |
internal.start(); |
|
170 |
} |
|
171 |
||
172 |
/** |
|
173 |
* Starts this recording after a delay. |
|
174 |
* <p> |
|
175 |
* After a successful invocation of this method, this recording is in the |
|
176 |
* {@code DELAYED} state. |
|
177 |
* |
|
178 |
* @param delay the time to wait before starting this recording, not |
|
179 |
* {@code null} |
|
180 |
* @throws IllegalStateException if the recording is not it the {@code NEW} state |
|
181 |
*/ |
|
182 |
public void scheduleStart(Duration delay) { |
|
183 |
Objects.requireNonNull(delay); |
|
184 |
internal.scheduleStart(delay); |
|
185 |
} |
|
186 |
||
187 |
/** |
|
188 |
* Stops this recording. |
|
189 |
* <p> |
|
190 |
* When a recording is stopped it can't be restarted. If this |
|
191 |
* recording has a destination, data is written to that destination and |
|
192 |
* the recording is closed. After a recording is closed, the data is no longer |
|
193 |
* available. |
|
194 |
* <p> |
|
195 |
* After a successful invocation of this method, this recording will be |
|
196 |
* in the {@code STOPPED} state. |
|
197 |
* |
|
198 |
* @return {@code true} if recording is stopped, {@code false} otherwise |
|
199 |
* |
|
200 |
* @throws IllegalStateException if the recording is not started or is already stopped |
|
201 |
* |
|
202 |
* @throws SecurityException if a security manager exists and the caller |
|
203 |
* doesn't have {@code FilePermission} to write to the destination |
|
204 |
* path |
|
205 |
* |
|
206 |
* @see #setDestination(Path) |
|
207 |
* |
|
208 |
*/ |
|
209 |
public boolean stop() { |
|
210 |
return internal.stop("Stopped by user"); |
|
211 |
} |
|
212 |
||
213 |
/** |
|
214 |
* Returns settings used by this recording. |
|
215 |
* <p> |
|
216 |
* Modifying the returned {@code Map} will not change the settings for this recording. |
|
217 |
* <p> |
|
218 |
* If no settings are set for this recording, an empty {@code Map} is |
|
219 |
* returned. |
|
220 |
* |
|
221 |
* @return recording settings, not {@code null} |
|
222 |
*/ |
|
223 |
public Map<String, String> getSettings() { |
|
224 |
return new HashMap<>(internal.getSettings()); |
|
225 |
} |
|
226 |
||
227 |
/** |
|
228 |
* Returns the current size of this recording in the disk repository, |
|
229 |
* measured in bytes. |
|
230 |
* <p> |
|
231 |
* The size is updated when recording buffers are flushed. If the recording is |
|
232 |
* not written to the disk repository the returned size is always {@code 0}. |
|
233 |
* |
|
234 |
* @return amount of recorded data, measured in bytes, or {@code 0} if the |
|
235 |
* recording is not written to the disk repository |
|
236 |
*/ |
|
237 |
public long getSize() { |
|
238 |
return internal.getSize(); |
|
239 |
} |
|
240 |
||
241 |
/** |
|
242 |
* Returns the time when this recording was stopped. |
|
243 |
* |
|
244 |
* @return the time, or {@code null} if this recording is not stopped |
|
245 |
*/ |
|
246 |
public Instant getStopTime() { |
|
247 |
return internal.getStopTime(); |
|
248 |
} |
|
249 |
||
250 |
/** |
|
251 |
* Returns the time when this recording was started. |
|
252 |
* |
|
253 |
* @return the the time, or {@code null} if this recording is not started |
|
254 |
*/ |
|
255 |
public Instant getStartTime() { |
|
256 |
return internal.getStartTime(); |
|
257 |
} |
|
258 |
||
259 |
/** |
|
260 |
* Returns the maximum size, measured in bytes, at which data is no longer kept in the disk repository. |
|
261 |
* |
|
262 |
* @return maximum size in bytes, or {@code 0} if no maximum size is set |
|
263 |
*/ |
|
264 |
public long getMaxSize() { |
|
265 |
return internal.getMaxSize(); |
|
266 |
} |
|
267 |
||
268 |
/** |
|
269 |
* Returns the length of time that the data is kept in the disk repository |
|
270 |
* before it is removed. |
|
271 |
* |
|
272 |
* @return maximum length of time, or {@code null} if no maximum length of time |
|
273 |
* has been set |
|
274 |
*/ |
|
275 |
public Duration getMaxAge() { |
|
276 |
return internal.getMaxAge(); |
|
277 |
} |
|
278 |
||
279 |
/** |
|
280 |
* Returns the name of this recording. |
|
281 |
* <p> |
|
282 |
* By default, the name is the same as the recording ID. |
|
283 |
* |
|
284 |
* @return the recording name, not {@code null} |
|
285 |
*/ |
|
286 |
public String getName() { |
|
287 |
return internal.getName(); |
|
288 |
} |
|
289 |
||
290 |
/** |
|
291 |
* Replaces all settings for this recording. |
|
292 |
* <p> |
|
293 |
* The following example shows how to set event settings for a recording. |
|
294 |
* |
|
295 |
* <pre> |
|
296 |
* <code> |
|
297 |
* Map{@literal <}String, String{@literal >} settings = new HashMap{@literal <}{@literal >}(); |
|
298 |
* settings.putAll(EventSettings.enabled("jdk.CPUSample").withPeriod(Duration.ofSeconds(2)).toMap()); |
|
299 |
* settings.putAll(EventSettings.enabled(MyEvent.class).withThreshold(Duration.ofSeconds(2)).withoutStackTrace().toMap()); |
|
300 |
* settings.put("jdk.ExecutionSample#period", "10 ms"); |
|
301 |
* recording.setSettings(settings); |
|
302 |
* </code> |
|
303 |
* </pre> |
|
304 |
* |
|
305 |
* The following example shows how to merge settings. |
|
306 |
* |
|
307 |
* <pre> |
|
308 |
* {@code |
|
309 |
* Map<String, String> settings = recording.getSettings(); |
|
310 |
* settings.putAll(additionalSettings); |
|
311 |
* recording.setSettings(settings); |
|
312 |
* } |
|
313 |
* </pre> |
|
314 |
* |
|
315 |
* @param settings the settings to set, not {@code null} |
|
316 |
*/ |
|
317 |
public void setSettings(Map<String, String> settings) { |
|
318 |
Objects.requireNonNull(settings); |
|
319 |
Map<String, String> sanitized = Utils.sanitizeNullFreeStringMap(settings); |
|
320 |
internal.setSettings(sanitized); |
|
321 |
} |
|
322 |
||
323 |
/** |
|
324 |
* Returns the recording state that this recording is currently in. |
|
325 |
* |
|
326 |
* @return the recording state, not {@code null} |
|
327 |
* |
|
328 |
* @see RecordingState |
|
329 |
*/ |
|
330 |
public RecordingState getState() { |
|
331 |
return internal.getState(); |
|
332 |
} |
|
333 |
||
334 |
/** |
|
335 |
* Releases all data that is associated with this recording. |
|
336 |
* <p> |
|
337 |
* After a successful invocation of this method, this recording is in the |
|
338 |
* {@code CLOSED} state. |
|
339 |
*/ |
|
340 |
@Override |
|
341 |
public void close() { |
|
342 |
internal.close(); |
|
343 |
} |
|
344 |
||
345 |
/** |
|
346 |
* Returns a clone of this recording, with a new recording ID and name. |
|
347 |
* |
|
348 |
* Clones are useful for dumping data without stopping the recording. After |
|
349 |
* a clone is created, the amount of data to copy is constrained |
|
350 |
* with the {@link #setMaxAge(Duration)} method and the {@link #setMaxSize(long)}method. |
|
351 |
* |
|
352 |
* @param stop {@code true} if the newly created copy should be stopped |
|
353 |
* immediately, {@code false} otherwise |
|
354 |
* @return the recording copy, not {@code null} |
|
355 |
*/ |
|
356 |
public Recording copy(boolean stop) { |
|
357 |
return internal.newCopy(stop); |
|
358 |
} |
|
359 |
||
360 |
/** |
|
361 |
* Writes recording data to a file. |
|
362 |
* <p> |
|
363 |
* Recording must be started, but not necessarily stopped. |
|
364 |
* |
|
365 |
* @param destination the location where recording data is written, not |
|
366 |
* {@code null} |
|
367 |
* |
|
368 |
* @throws IOException if the recording can't be copied to the specified |
|
369 |
* location |
|
370 |
* |
|
371 |
* @throws SecurityException if a security manager exists and the caller doesn't |
|
372 |
* have {@code FilePermission} to write to the destination path |
|
373 |
*/ |
|
374 |
public void dump(Path destination) throws IOException { |
|
375 |
Objects.requireNonNull(destination); |
|
50745 | 376 |
internal.dump(new WriteableUserPath(destination)); |
377 |
||
50113 | 378 |
} |
379 |
||
380 |
/** |
|
381 |
* Returns {@code true} if this recording uses the disk repository, {@code false} otherwise. |
|
382 |
* <p> |
|
383 |
* If no value is set, {@code true} is returned. |
|
384 |
* |
|
385 |
* @return {@code true} if the recording uses the disk repository, {@code false} |
|
386 |
* otherwise |
|
387 |
*/ |
|
388 |
public boolean isToDisk() { |
|
389 |
return internal.isToDisk(); |
|
390 |
} |
|
391 |
||
392 |
/** |
|
393 |
* Determines how much data is kept in the disk repository. |
|
394 |
* <p> |
|
395 |
* To control the amount of recording data that is stored on disk, the maximum |
|
396 |
* amount of data to retain can be specified. When the maximum limit is |
|
397 |
* exceeded, the Java Virtual Machine (JVM) removes the oldest chunk to make |
|
398 |
* room for a more recent chunk. |
|
399 |
* <p> |
|
400 |
* If neither maximum limit or the maximum age is set, the size of the |
|
401 |
* recording may grow indefinitely. |
|
402 |
* |
|
403 |
* @param maxSize the amount of data to retain, {@code 0} if infinite |
|
404 |
* |
|
405 |
* @throws IllegalArgumentException if <code>maxSize</code> is negative |
|
406 |
* |
|
407 |
* @throws IllegalStateException if the recording is in {@code CLOSED} state |
|
408 |
*/ |
|
409 |
public void setMaxSize(long maxSize) { |
|
410 |
if (maxSize < 0) { |
|
411 |
throw new IllegalArgumentException("Max size of recording can't be negative"); |
|
412 |
} |
|
413 |
internal.setMaxSize(maxSize); |
|
414 |
} |
|
415 |
||
58863 | 416 |
/** |
417 |
* Determines how often events are made available for streaming. |
|
418 |
* |
|
419 |
* @param interval the interval at which events are made available for streaming. |
|
420 |
* |
|
421 |
* @throws IllegalArgumentException if {@code interval} is negative |
|
422 |
* |
|
423 |
* @throws IllegalStateException if the recording is in the {@code CLOSED} state |
|
424 |
* |
|
425 |
* @since 14 |
|
426 |
*/ |
|
427 |
public void setFlushInterval(Duration interval) { |
|
428 |
Objects.nonNull(interval); |
|
429 |
if (interval.isNegative()) { |
|
430 |
throw new IllegalArgumentException("Stream interval can't be negative"); |
|
431 |
} |
|
432 |
internal.setFlushInterval(interval); |
|
433 |
} |
|
434 |
||
435 |
/** |
|
436 |
* Returns how often events are made available for streaming purposes. |
|
437 |
* |
|
438 |
* @return the flush interval, or {@code null} if no interval has been set |
|
439 |
* |
|
440 |
* @since 14 |
|
441 |
*/ |
|
442 |
public Duration getFlushInterval() { |
|
443 |
return internal.getFlushInterval(); |
|
444 |
} |
|
445 |
||
50113 | 446 |
/** |
447 |
* Determines how far back data is kept in the disk repository. |
|
448 |
* <p> |
|
449 |
* To control the amount of recording data stored on disk, the maximum length of |
|
450 |
* time to retain the data can be specified. Data stored on disk that is older |
|
451 |
* than the specified length of time is removed by the Java Virtual Machine (JVM). |
|
452 |
* <p> |
|
453 |
* If neither maximum limit or the maximum age is set, the size of the |
|
454 |
* recording may grow indefinitely. |
|
455 |
* |
|
456 |
* @param maxAge the length of time that data is kept, or {@code null} if infinite |
|
457 |
* |
|
458 |
* @throws IllegalArgumentException if <code>maxAge</code> is negative |
|
459 |
* |
|
460 |
* @throws IllegalStateException if the recording is in the {@code CLOSED} state |
|
461 |
*/ |
|
462 |
public void setMaxAge(Duration maxAge) { |
|
463 |
if (maxAge != null && maxAge.isNegative()) { |
|
464 |
throw new IllegalArgumentException("Max age of recording can't be negative"); |
|
465 |
} |
|
466 |
internal.setMaxAge(maxAge); |
|
467 |
} |
|
468 |
||
469 |
/** |
|
470 |
* Sets a location where data is written on recording stop, or |
|
471 |
* {@code null} if data is not to be dumped. |
|
472 |
* <p> |
|
473 |
* If a destination is set, this recording is automatically closed |
|
474 |
* after data is successfully copied to the destination path. |
|
475 |
* <p> |
|
476 |
* If a destination is <em>not</em> set, Flight Recorder retains the |
|
477 |
* recording data until this recording is closed. Use the {@link #dump(Path)} method to |
|
478 |
* manually write data to a file. |
|
479 |
* |
|
480 |
* @param destination the destination path, or {@code null} if recording should |
|
481 |
* not be dumped at stop |
|
482 |
* |
|
483 |
* @throws IllegalStateException if recording is in the {@code STOPPED} or |
|
484 |
* {@code CLOSED} state. |
|
485 |
* |
|
486 |
* @throws SecurityException if a security manager exists and the caller |
|
487 |
* doesn't have {@code FilePermission} to read, write, and delete the |
|
488 |
* {@code destination} file |
|
489 |
* |
|
490 |
* @throws IOException if the path is not writable |
|
491 |
*/ |
|
492 |
public void setDestination(Path destination) throws IOException { |
|
493 |
internal.setDestination(destination != null ? new WriteableUserPath(destination) : null); |
|
494 |
} |
|
495 |
||
496 |
/** |
|
497 |
* Returns the destination file, where recording data is written when the |
|
498 |
* recording stops, or {@code null} if no destination is set. |
|
499 |
* |
|
500 |
* @return the destination file, or {@code null} if not set. |
|
501 |
*/ |
|
502 |
public Path getDestination() { |
|
503 |
WriteableUserPath usp = internal.getDestination(); |
|
504 |
if (usp == null) { |
|
505 |
return null; |
|
506 |
} else { |
|
507 |
return usp.getPotentiallyMaliciousOriginal(); |
|
508 |
} |
|
509 |
} |
|
510 |
||
511 |
/** |
|
512 |
* Returns a unique ID for this recording. |
|
513 |
* |
|
514 |
* @return the recording ID |
|
515 |
*/ |
|
516 |
public long getId() { |
|
517 |
return internal.getId(); |
|
518 |
} |
|
519 |
||
520 |
/** |
|
521 |
* Sets a human-readable name (for example, {@code "My Recording"}). |
|
522 |
* |
|
523 |
* @param name the recording name, not {@code null} |
|
524 |
* |
|
525 |
* @throws IllegalStateException if the recording is in {@code CLOSED} state |
|
526 |
*/ |
|
527 |
public void setName(String name) { |
|
528 |
Objects.requireNonNull(name); |
|
529 |
internal.setName(name); |
|
530 |
} |
|
531 |
||
532 |
/** |
|
533 |
* Sets whether this recording is dumped to disk when the JVM exits. |
|
534 |
* |
|
535 |
* @param dumpOnExit if this recording should be dumped when the JVM exits |
|
536 |
*/ |
|
537 |
public void setDumpOnExit(boolean dumpOnExit) { |
|
538 |
internal.setDumpOnExit(dumpOnExit); |
|
539 |
} |
|
540 |
||
541 |
/** |
|
542 |
* Returns whether this recording is dumped to disk when the JVM exits. |
|
543 |
* <p> |
|
544 |
* If dump on exit is not set, {@code false} is returned. |
|
545 |
* |
|
546 |
* @return {@code true} if the recording is dumped on exit, {@code false} |
|
547 |
* otherwise. |
|
548 |
*/ |
|
549 |
public boolean getDumpOnExit() { |
|
550 |
return internal.getDumpOnExit(); |
|
551 |
} |
|
552 |
||
553 |
/** |
|
554 |
* Determines whether this recording is continuously flushed to the disk |
|
555 |
* repository or data is constrained to what is available in memory buffers. |
|
556 |
* |
|
557 |
* @param disk {@code true} if this recording is written to disk, |
|
558 |
* {@code false} if in-memory |
|
559 |
* |
|
560 |
*/ |
|
561 |
public void setToDisk(boolean disk) { |
|
562 |
internal.setToDisk(disk); |
|
563 |
} |
|
564 |
||
565 |
/** |
|
566 |
* Creates a data stream for a specified interval. |
|
567 |
* <p> |
|
568 |
* The stream may contain some data outside the specified range. |
|
569 |
* |
|
570 |
* @param the start start time for the stream, or {@code null} to get data from |
|
571 |
* start time of the recording |
|
572 |
* |
|
573 |
* @param the end end time for the stream, or {@code null} to get data until the |
|
574 |
* present time. |
|
575 |
* |
|
576 |
* @return an input stream, or {@code null} if no data is available in the |
|
577 |
* interval. |
|
578 |
* |
|
579 |
* @throws IllegalArgumentException if {@code end} happens before |
|
580 |
* {@code start} |
|
581 |
* |
|
582 |
* @throws IOException if a stream can't be opened |
|
583 |
*/ |
|
584 |
public InputStream getStream(Instant start, Instant end) throws IOException { |
|
585 |
if (start != null && end != null && end.isBefore(start)) { |
|
586 |
throw new IllegalArgumentException("End time of requested stream must not be before start time"); |
|
587 |
} |
|
588 |
return internal.open(start, end); |
|
589 |
} |
|
590 |
||
591 |
/** |
|
592 |
* Returns the specified duration for this recording, or {@code null} if no |
|
593 |
* duration is set. |
|
594 |
* <p> |
|
595 |
* The duration can be set only when the recording is in the |
|
596 |
* {@link RecordingState#NEW} state. |
|
597 |
* |
|
598 |
* @return the desired duration of the recording, or {@code null} if no duration |
|
599 |
* has been set. |
|
600 |
*/ |
|
601 |
public Duration getDuration() { |
|
602 |
return internal.getDuration(); |
|
603 |
} |
|
604 |
||
605 |
/** |
|
606 |
* Sets a duration for how long a recording runs before it stops. |
|
607 |
* <p> |
|
608 |
* By default, a recording has no duration ({@code null}). |
|
609 |
* |
|
610 |
* @param duration the duration, or {@code null} if no duration is set |
|
611 |
* |
|
612 |
* @throws IllegalStateException if recording is in the {@code STOPPED} or {@code CLOSED} state |
|
613 |
*/ |
|
614 |
public void setDuration(Duration duration) { |
|
615 |
internal.setDuration(duration); |
|
616 |
} |
|
617 |
||
618 |
/** |
|
619 |
* Enables the event with the specified name. |
|
620 |
* <p> |
|
621 |
* If multiple events have the same name (for example, the same class is loaded |
|
622 |
* in different class loaders), then all events that match the name are enabled. To |
|
623 |
* enable a specific class, use the {@link #enable(Class)} method or a {@code String} |
|
624 |
* representation of the event type ID. |
|
625 |
* |
|
626 |
* @param name the settings for the event, not {@code null} |
|
627 |
* |
|
628 |
* @return an event setting for further configuration, not {@code null} |
|
629 |
* |
|
630 |
* @see EventType |
|
631 |
*/ |
|
632 |
public EventSettings enable(String name) { |
|
633 |
Objects.requireNonNull(name); |
|
634 |
RecordingSettings rs = new RecordingSettings(this, name); |
|
635 |
rs.with("enabled", "true"); |
|
636 |
return rs; |
|
637 |
} |
|
638 |
||
639 |
/** |
|
640 |
* Disables event with the specified name. |
|
641 |
* <p> |
|
642 |
* If multiple events with same name (for example, the same class is loaded |
|
643 |
* in different class loaders), then all events that match the |
|
644 |
* name is disabled. To disable a specific class, use the |
|
645 |
* {@link #disable(Class)} method or a {@code String} representation of the event |
|
646 |
* type ID. |
|
647 |
* |
|
648 |
* @param name the settings for the event, not {@code null} |
|
649 |
* |
|
650 |
* @return an event setting for further configuration, not {@code null} |
|
651 |
* |
|
652 |
*/ |
|
653 |
public EventSettings disable(String name) { |
|
654 |
Objects.requireNonNull(name); |
|
655 |
RecordingSettings rs = new RecordingSettings(this, name); |
|
656 |
rs.with("enabled", "false"); |
|
657 |
return rs; |
|
658 |
} |
|
659 |
||
660 |
/** |
|
661 |
* Enables event. |
|
662 |
* |
|
663 |
* @param eventClass the event to enable, not {@code null} |
|
664 |
* |
|
665 |
* @throws IllegalArgumentException if {@code eventClass} is an abstract |
|
666 |
* class or not a subclass of {@link Event} |
|
667 |
* |
|
668 |
* @return an event setting for further configuration, not {@code null} |
|
669 |
*/ |
|
670 |
public EventSettings enable(Class<? extends Event> eventClass) { |
|
671 |
Objects.requireNonNull(eventClass); |
|
672 |
RecordingSettings rs = new RecordingSettings(this, eventClass); |
|
673 |
rs.with("enabled", "true"); |
|
674 |
return rs; |
|
675 |
} |
|
676 |
||
677 |
/** |
|
678 |
* Disables event. |
|
679 |
* |
|
680 |
* @param eventClass the event to enable, not {@code null} |
|
681 |
* |
|
682 |
* @throws IllegalArgumentException if {@code eventClass} is an abstract |
|
683 |
* class or not a subclass of {@link Event} |
|
684 |
* |
|
685 |
* @return an event setting for further configuration, not {@code null} |
|
686 |
* |
|
687 |
*/ |
|
688 |
public EventSettings disable(Class<? extends Event> eventClass) { |
|
689 |
Objects.requireNonNull(eventClass); |
|
690 |
RecordingSettings rs = new RecordingSettings(this, eventClass); |
|
691 |
rs.with("enabled", "false"); |
|
692 |
return rs; |
|
693 |
} |
|
694 |
||
695 |
// package private |
|
696 |
PlatformRecording getInternal() { |
|
697 |
return internal; |
|
698 |
} |
|
699 |
||
700 |
private void setSetting(String id, String value) { |
|
701 |
Objects.requireNonNull(id); |
|
702 |
Objects.requireNonNull(value); |
|
703 |
internal.setSetting(id, value); |
|
704 |
} |
|
705 |
||
706 |
} |