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