blob: c674480ea6d8c047635ad7b8389da3a07fefae0f [file] [log] [blame] [edit]
// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
/// Interact with developer tools such as the debugger and inspector.
///
/// This is a specialized library intended for interacting with the Dart runtime
/// programmatically for debugging and inspection. Sample uses include advanced
/// debugging, and creating developer tools.
///
/// This library has platform specific implementations for Dart web
/// and Dart Native (VM). A specific platform may not support all operations.
///
/// The functionality provided by this library is generally only available
/// to Dart code run in development mode, e.g., `dart run`, and not in production
/// mode, e.g., the output of `dart compile exe`.
///
/// ## Debugging
/// The [debugger] function can be used to stop the program as if a breakpoint
/// was hit. The breakpoint will be placed right after the call to `debugger`.
/// This functionality can be useful for triggering breakpoints based on logic
/// in the code.
///
/// Example:
///
/// ```dart template:main
/// var counter = 0;
/// final someInterestingValue = 1000;
/// while (true) {
/// if (counter == someInterestingValue) {
/// // Trigger a breakpoint in the debugger.
/// debugger();
/// }
/// counter++;
/// }
/// ```
///
/// When executed with `dart run --observe`, and opened in DevTools, the
/// debugger will be stopped with `counter` at the value `1000`.
///
/// ## Inspection
/// Developer tools, such as Dart DevTools, connected to the runtime system
/// may allow for inspecting execution timing in a "timeline" view.
/// The static methods of [Timeline] can add extra information and timing events
/// to this view.
///
/// Example:
///
/// ```dart
/// void main() {
/// Timeline.timeSync('Calculation loop', () {
/// for (var i = 30; i < 50; i++) {
/// Timeline.timeSync('fib($i)', () {
/// fibonacci(i);
/// });
/// }
/// });
/// }
///
/// int fibonacci(int n) => (n < 2) ? n : fibonacci(n - 2) + fibonacci(n - 1);
/// ```
///
/// When executed with `dart run --observe`, and opened in DevTools,
/// the Performance tab will display a timeline containing the annotations
/// passed to `timeSync`.
///
/// ## Developer tools
/// A developer tool, like the debugger built into the `dart` command,
/// may access information about the running application
/// exposed by the runtime system,
/// using the [Service] and [ServiceProtocolInfo] classes.
///
/// {@category Core}
library dart.developer;
import 'dart:_internal' show checkNotNullable, Since;
import 'dart:async';
import 'dart:collection';
import 'dart:convert';
import 'dart:isolate' show Isolate, RawReceivePort, SendPort;
part 'extension.dart';
part 'http_profiling.dart';
part 'profiler.dart';
part 'service.dart';
part 'timeline.dart';
/// If [when] is true, stop the program as if a breakpoint were hit at the
/// following statement.
///
/// Returns the value of [when]. Some debuggers may display [message].
///
/// NOTE: When invoked, the isolate will not return until a debugger
/// continues execution. When running in the Dart VM, the behaviour is the same
/// regardless of whether or not a debugger is connected. When compiled to
/// JavaScript, this uses the "debugger" statement, and behaves exactly as
/// that does.
external bool debugger({bool when = true, String? message});
/// Send a reference to [object] to any attached debuggers.
///
/// Debuggers may open an inspector on the object. Returns the argument.
external Object? inspect(Object? object);
/// Emit a log event, which can can viewed using the DevTools
/// [Logging view](https://docs.flutter.dev/tools/devtools/logging).
///
/// This function was designed to map closely to the logging information
/// collected by `package:logging`.
///
/// - [message] is the log message
/// - [time] (optional) is the timestamp
/// - [sequenceNumber] (optional) is a monotonically increasing sequence number
/// - [level] (optional) is the severity level (a value between 0 and 2000); see
/// the `package:logging` `Level` class for an overview of the possible values
/// - [name] (optional) is the name of the source of the log message
/// - [zone] (optional) the zone where the log was emitted
/// - [error] (optional) an error object associated with this log event
/// - [stackTrace] (optional) a stack trace associated with this log event
external void log(
String message, {
DateTime? time,
int? sequenceNumber,
int level = 0,
String name = '',
Zone? zone,
Object? error,
StackTrace? stackTrace,
});
/// Current reachability barrier state.
///
/// A reachability barrier state that provides a way to synchronize on
/// reachability. At value 'x', any object that became unreachable during
/// 'value' < 'x' has been collected and any associated finalizers have been
/// scheduled for execution, i.e. the non-execution of a finalizer reliably
/// indicates the object is still reachable in the previous barrier state.
///
/// Objects that became unreachable in the current barrier state may have not
/// yet been collected or finalized.
///
/// NOTE: There are no guarantees of forward progress. An implementation may
/// return the same value forever for this barrier state.
@Since('2.19')
external int get reachabilityBarrier;
/// Types of timeline recorders supported by the VM.
@Since('3.11')
enum TimelineRecorder {
/// [Perfetto](https://ui.perfetto.dev)'s protobuf based format.
///
/// Supports both profiling and tracing data.
///
/// Scheme is available in [Perfetto docs](https://perfetto.dev/docs/reference/trace-packet-proto).
perfetto,
/// Chrome's JSON based format viewable by [Catapult](chrome://tracing).
///
/// Supports only tracing data.
///
/// Scheme is described in [here](https://docs.google.com/document/d/1CvAClvFfyA5R-PhYUmn5OOQtYMH4h6I0nSsKchNAySU/preview?tab=t.0).
chrome,
/// Emits platform specific timeline events.
///
/// * On Linux and Android this means writing events into
/// [ftrace](https://docs.kernel.org/trace/ftrace.html) buffer.
/// * On Mac OS X this uses [signposts](https://developer.apple.com/documentation/os/recording-performance-data).
/// * On Fuchsia it uses [Fuchsia tracing system](https://fuchsia.dev/fuchsia-src/concepts/kernel/tracing-system).
/// * Not supported on Windows.
///
systrace,
}
/// Specific sets of events whose recording can be enabled separately.
@Since('3.11')
enum TimelineStream {
/// Calls to `Dart_*` VM C API functions.
api,
/// Events related to compilation to machine code.
compiler,
/// Detailed timing information about compiler phases.
compilerVerbose,
/// Events created via [Timeline] APIs.
dart,
/// Events related to debugger.
debugger,
/// Events created by `Dart_RecordTimelineEvent`.
embedder,
/// Events related to garbage collection and/or heap iteration.
gc,
/// Isolate and isolate group lifecycle events such as startup and shutdown.
isolate,
/// Events representing `dart:async` microtasks. VM will only populate this
/// stream with events if it is started with `--profile-microtasks`.
microtask,
/// VM lifecycle events such as startup and shutdown.
vm,
}
/// Functionality available on the native runtime.
@Since('3.0')
abstract final class NativeRuntime {
/// The build ID for the running application.
///
/// The build ID of an application is a string containing a hexadecimal
/// representation of an arbitrarily sized sequence of bytes. This string
/// can be used to match a specific ahead-of-time compiled version of an
/// application, for example, to determine which debugging artifacts emitted
/// during compilation should be used to translate crash and error reports.
///
/// The build ID is only available for ahead-of-time compiled programs. If a
/// build ID is not available, the value is `null`.
@Since('3.1')
external static String? get buildId;
/// Writes a snapshot of the heap to [filepath].
///
/// The [filepath] should be a native file path that can be opened for writing.
/// Relative paths will be relative to the current working directory. If the
/// file already exists it will be overwritten.
///
/// **WARNING**: Only works on a native runtime in certain configurations. An
/// [UnsupportedError] error is thrown if this functionality is not available
/// (e.g. in product mode, in non-standalone VM, ...)
///
/// NOTE: This is an experimental function. We reserve the right to change
/// or remove it in the future.
external static void writeHeapSnapshotToFile(String filepath);
/// Tells runtime to write timeline data using [recorder].
///
/// Timeline recording is enabled for the whole runtime and not for any
/// specific isolate or isolate group.
///
/// Once started timeline recording will continue until it is stopped by
/// [stopStreamingTimeline].
///
/// Some recorders write into a specific file (specified by [path]), while
/// others write to system wide recording buffer.
///
/// The [streams] specifies which timeline streams to enable. Only
/// [TimelineStream.dart] and [TimelineStream.gc] are enabled by default.
///
/// If [recorder] supports profiling data then setting [enableProfiler] to
/// `true` will turn on sampling profiler, which will collect profiling
/// samples with frequency specified by [samplingInterval]. These samples
/// will then written into the timeline.
///
/// Throws [ArgumentError] iff:
///
/// * [path] is specified but [recorder] writes to a fixed location.
/// * [path] is not specified and [recorder] requires it.
/// * [enableProfiler] is `true` and [recorder] does not support writing out
/// profiling data.
/// * [samplingInterval] is too small.
@Since('3.11')
external static void streamTimelineTo(
TimelineRecorder recorder, {
String? path,
List<TimelineStream> streams = const [
TimelineStream.dart,
TimelineStream.gc,
],
bool enableProfiler = false,
Duration samplingInterval = const Duration(microseconds: 1000),
});
/// Finishes capturing of timeline data started by [streamTimelineTo].
@Since('3.11')
external static void stopStreamingTimeline();
}