| // 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(); |
| } |