trace.dart 2.92 KB
Newer Older
1 2 3 4 5
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

import 'dart:async';
6
import 'dart:convert';
7

8
import '../base/common.dart';
9
import '../base/file_system.dart';
10
import '../base/utils.dart';
11
import '../cache.dart';
12
import '../globals.dart';
13
import '../runner/flutter_command.dart';
14
import '../tracing.dart';
15

16
class TraceCommand extends FlutterCommand {
17
  TraceCommand() {
18
    requiresPubspecYaml();
19 20 21 22 23
    argParser.addFlag('start', negatable: false, help: 'Start tracing.');
    argParser.addFlag('stop', negatable: false, help: 'Stop tracing.');
    argParser.addOption('out', help: 'Specify the path of the saved trace file.');
    argParser.addOption('duration',
        defaultsTo: '10', abbr: 'd', help: 'Duration in seconds to trace.');
24
    argParser.addOption('debug-port',
25
        defaultsTo: kDefaultObservatoryPort.toString(),
26
        help: 'Local port where the observatory is listening.');
27 28
  }

29
  @override
30
  final String name = 'trace';
31 32

  @override
33
  final String description = 'Start and stop tracing for a running Flutter app.';
34 35

  @override
Devon Carew's avatar
Devon Carew committed
36 37 38 39
  final String usageFooter =
    '\`trace\` called with no arguments will automatically start tracing, delay a set amount of\n'
    'time (controlled by --duration), and stop tracing. To explicitly control tracing, call trace\n'
    'with --start and later with --stop.';
40 41

  @override
42
  Future<Null> runCommand() async {
43
    final int observatoryPort = int.parse(argResults['debug-port']);
44

45 46
    // TODO(danrubel): this will break if we move to the new observatory URL
    // See https://github.com/flutter/flutter/issues/7038
47
    final Uri observatoryUri = Uri.parse('http://127.0.0.1:$observatoryPort');
48

49 50 51
    Tracing tracing;

    try {
52
      tracing = await Tracing.connect(observatoryUri);
53
    } catch (error) {
54
      throwToolExit('Error connecting to observatory: $error');
55 56
    }

57 58
    Cache.releaseLockEarly();

59 60 61 62
    if ((!argResults['start'] && !argResults['stop']) ||
        (argResults['start'] && argResults['stop'])) {
      // Setting neither flags or both flags means do both commands and wait
      // duration seconds in between.
63
      await tracing.startTracing();
Ian Hickson's avatar
Ian Hickson committed
64
      await new Future<Null>.delayed(
65
        new Duration(seconds: int.parse(argResults['duration'])),
66
        () => _stopTracing(tracing)
67
      );
68
    } else if (argResults['stop']) {
69
      await _stopTracing(tracing);
70
    } else {
71
      await tracing.startTracing();
72 73 74
    }
  }

75
  Future<Null> _stopTracing(Tracing tracing) async {
76
    final Map<String, dynamic> timeline = await tracing.stopTracingAndDownloadTimeline();
77
    File localFile;
78 79

    if (argResults['out'] != null) {
80
      localFile = fs.file(argResults['out']);
81
    } else {
82
      localFile = getUniqueFile(fs.currentDirectory, 'trace', 'json');
83
    }
84 85

    await localFile.writeAsString(JSON.encode(timeline));
86

87
    printStatus('Trace file saved to ${localFile.path}');
88 89
  }
}