Flutter性能监控插件instana_agent的使用

发布于 1周前 作者 eggper 来自 Flutter

Flutter性能监控插件instana_agent的使用

Instana agent for Flutter

Changelog | Contributing


Instana agent 使 Flutter 应用程序能够将监控数据发送到 Instana。

Requirements

  • Flutter 版本 1.20.0 及以上
  • Dart 版本介于 2.12.0 和 4.0.0 之间

Installation

Instana agent Flutter 包可通过 pub.dev 获取。

您可以像往常一样将其添加到应用程序中:

  1. 打开 pubspec.yaml 文件(位于应用文件夹内),并在 dependencies 下添加 instana_agent:
  2. 安装它
    • 从终端:运行 flutter pub get
    • 或者:
      • 从 Android Studio/IntelliJ:点击 pubspec.yaml 顶部操作带中的 Packages get
      • 从 VS Code:点击 pubspec.yaml 顶部操作带右侧的 Get Packages

Initialization

在 Dart 文件中导入包:

import 'package:instana_agent/instana_agent.dart';

如果需要,停止并重新启动应用程序。

在尽可能早的地方设置 Instana。例如,在 initState() 中:

@override
void initState() {
  super.initState();
  InstanaAgent.setup(key: 'YOUR-INSTANA-KEY', reportingUrl: 'YOUR-REPORTING_URL');
}

Tracking View changes

在初始化 Instana agent 后的任何时间点:

InstanaAgent.setView('Home');

Tracking HTTP requests

在初始化 Instana agent 后的任何时间点:

InstanaAgent.startCapture(url: 'https://example.com/success', method: 'GET').then((marker) => marker
    ..responseStatusCode = 200
    ..responseSizeBody = 1000
    ..responseSizeBodyDecoded = 2400
    ..finish());

推荐创建自己的 InstrumentedHttpClient 扩展 http.BaseClient,如以下代码片段所示:

class _InstrumentedHttpClient extends BaseClient {
  _InstrumentedHttpClient(this._inner);

  final Client _inner;

  @override
  Future<StreamedResponse> send(BaseRequest request) async {
    final Marker marker = await InstanaAgent.startCapture(url: request.url.toString(), method: request.method);

    StreamedResponse response;
    try {
      response = await _inner.send(request);
      marker
        ..responseStatusCode = response.statusCode
        ..responseSizeBody = response.contentLength
        ..backendTracingID = BackendTracingIDParser.fromHeadersMap(response.headers)
        ..responseHeaders = response.headers;
    } finally {
      await marker.finish();
    }

    return response;
  }
}

class _MyAppState extends State<MyApp> {
  Future<void> httpRequest() async {
    final _InstrumentedHttpClient httpClient = _InstrumentedHttpClient(Client());
    final Request request = Request("GET", Uri.parse("https://www.instana.com"));
    httpClient.send(request);
  }
}

Error handling

所有代理接口返回一个异步的 Future。错误被包装在一个 PlatformException 类型的异常中。

建议开发者遵循 Futures 错误处理技术,至少记录任何可能的错误。

例如:

InstanaAgent.setup(key: 'KEY', reportingUrl: 'REPORTING_URL')
    .catchError((e) => 
            log("Captured PlatformException during Instana setup: $e")
        );

或在异步函数中:

try {
  var result = await InstanaAgent.setup(key: 'KEY', reportingUrl: 'REPORTING_URL');
} catch (e) {
  log("Captured PlatformException during Instana setup: $e");
}

How to enable native http capture

自 flutter-agent 版本 2.5.0 起,我们可以捕获 iOS 平台(使用 Swift 或 Objective C 语言)和 Android 平台(使用 Kotlin 或 Java 语言)内部的 HTTP 调用,默认情况下是禁用的。

请修改您的 Instana 设置调用如下:

var options = SetupOptions();
options.collectionEnabled = true;
options.captureNativeHttp = true;
InstanaAgent.setup(key: 'YOUR-INSTANA-KEY', reportingUrl: 'YOUR-REPORTING_URL', options: options);

对于 Android 平台,还需做以下两个更改:

  1. 在项目级别的 build.gradle 文件中,向 classpath 部分添加 android-agent-plugin
buildscript {
  ext.native_instana_version = '6.0.19' //版本必须与 flutter-agent 使用的 android-agent 版本相同
  // 其他设置在此处
  dependencies {
    // 其他 classpaths 在此处
    classpath "com.instana:android-agent-plugin:$native_instana_version"
  }
}
  1. 在 app 级别的 build.gradle 文件中,在应用 flutter.gradle 之前应用 android-agent-plugin。
apply plugin: 'com.instana.android-agent-plugin'
apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle"

How to enable http auto capture

自 flutter-agent 版本 2.6.0 起,我们可以在 Dart 内自动捕获 HTTP 调用。设置您的 HttpOverrides.global 如下:

void main() {
  HttpOverrides.global = InstanaHttpOverrides();
  runApp(const MyApp());
}

如果您已经有一个用于其他目的的 HttpOverrides 版本,请将 InstanaHttpOverrides 类的功能合并到您的类中,并自行维护合并后的类。链式调用多个 HttpOverrides 是容易出错的。

如果您启用了 HTTP 自动捕获,请停止使用上述示例代码如 InstanaAgent.startCapture()、_InstrumentedHttpClient(),否则会发生双重捕获。确保始终需要 InstanaAgent.setup()。

More

有关此包的完整文档,包括 custom events 等内容,请参阅 Instana 的公共文档页面

请还查看此仓库中的 Flutter 示例以获取简单的用法演示。

示例 Demo

以下是一个完整的示例 demo,展示了如何使用 Instana agent 进行性能监控:

/*
 * (c) Copyright IBM Corp. 2021
 * (c) Copyright Instana Inc. and contributors 2021
 */

import 'dart:async';
import 'dart:convert';
import 'dart:math';

import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
import 'package:instana_agent/instana_agent.dart';

import 'http_client.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatefulWidget {
  @override
  _MyAppState createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  late Future<Album> futureAlbum;

  @override
  void initState() {
    super.initState();

    /// 初始化 Instana。必须尽早且仅运行一次
    setupInstana();

    /// 可选
    futureAlbum = fetchAlbum();
  }

  void setupInstana() async {
    var options = SetupOptions();
    options.collectionEnabled = false;
    // options.slowSendInterval = 60.0; // 启用慢速发送模式,发送间隔为 60 秒
    // options.usiRefreshTimeIntervalInHrs = 24.0; // 每 24 小时刷新一次用户会话 ID
    bool ret = await InstanaAgent.setup(key: 'key', reportingUrl: 'URL', options: options);
    if (!ret) {
      // 错误处理
      if (kDebugMode) {
        print("InstanaAgent setup failed");
      }
    }

    setUserIdentifiers();

    InstanaAgent.setCollectionEnabled(true);

    /// 可选
    setView();

    InstanaAgent.setCaptureHeaders(regex: [
      'x-ratelimit-limit',
      'x-ratelimit-remaining',
      'x-ratelimit-reset'
    ]);

    InstanaAgent.redactHTTPQuery(regex: ['uid', 'user']);

    /// 可选
    reportCustomEvents();
  }

  /// 设置用户标识符
  ///
  /// 这些将附加到所有后续的 beacon 上
  setUserIdentifiers() {
    InstanaAgent.setUserID('1234567890');
    InstanaAgent.setUserName('Boty McBotFace');
    InstanaAgent.setUserEmail('boty@mcbot.com');
  }

  /// 设置视图允许在 Instana Dashboard 的 Session 时间轴中更容易地进行逻辑分割
  setView() {
    InstanaAgent.setView('Home');
  }

  /// 在任何时候都可以向 Instana beacon 添加元数据并生成事件
  Future<void> reportCustomEvents() async {
    InstanaAgent.setMeta(key: 'exampleGlobalKey', value: 'exampleGlobalValue');

    await InstanaAgent.reportEvent(name: 'simpleCustomEvent');
    await InstanaAgent.reportEvent(name: 'customEventWithMetric',
        options: EventOptions()
          ..customMetric = 12345.678);
    await InstanaAgent.reportEvent(
        name: 'complexCustomEvent',
        options: EventOptions()
          ..viewName = 'customViewName'
          ..startTime = DateTime.now().millisecondsSinceEpoch
          ..duration = 2 * 1000);
    await InstanaAgent.reportEvent(
        name: 'advancedCustomEvent',
        options: EventOptions()
          ..viewName = 'customViewName'
          ..startTime = DateTime.now().millisecondsSinceEpoch
          ..duration = 3 * 1000
          ..meta = {
            'customKey1': 'customValue1',
            'customKey2': 'customValue2'
          });
    await InstanaAgent.startCapture(
            url: 'https://example.com/failure', method: 'GET')
        .then((marker) => marker
          ..responseStatusCode = 500
          ..responseSizeBody = 1000
          ..responseSizeBodyDecoded = 2400
          ..errorMessage = 'Download of album failed'
          ..finish());
    await InstanaAgent.startCapture(
            url: 'https://example.com/cancel', method: 'POST')
        .then((marker) => marker.cancel());
  }

  Future<Album> fetchAlbum() async {
    final InstrumentedHttpClient httpClient =
        InstrumentedHttpClient(http.Client());

    Random random = new Random();
    var id = random.nextInt(100);
    var uid = random.nextInt(1000);
    var url = 'https://jsonplaceholder.typicode.com/albums/$id?uid=$uid';
    final http.Request request = http.Request("GET", Uri.parse(url));

    final response = await httpClient.send(request);
    if (response.statusCode == 200) {
      var responseBody = await response.stream.bytesToString();
      return Album.fromJson(jsonDecode(responseBody));
    } else {
      throw Exception('Failed to load album');
    }
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: const Text('Plugin example app'),
        ),
        body: Center(
          child: Column(
            children: <Widget>[
              ElevatedButton(
                  style: ElevatedButton.styleFrom(
                    foregroundColor: Colors.white,
                    padding: const EdgeInsets.all(8.0),
                    textStyle: const TextStyle(fontSize: 16, color: Colors.blue),
                  ),
                  onPressed: () {
                    this.setState(() {
                      futureAlbum = fetchAlbum();
                    });
                  },
                  child: Text("Reload")),
              FutureBuilder<Album>(
                future: futureAlbum,
                builder: (context, snapshot) {
                  if (snapshot.hasData) {
                    return Text("Title: " +
                        snapshot.data!.title +
                        "\nID: " +
                        snapshot.data!.id.toString());
                  } else if (snapshot.hasError) {
                    return Text("${snapshot.error}");
                  } else {
                    return Text("Loading...");
                  }
                },
              )
            ],
          ),
        ),
      ),
    );
  }
}

class Album {
  final int userId;
  final int id;
  final String title;

  Album({required this.userId, required this.id, required this.title});

  factory Album.fromJson(Map<String, dynamic> json) {
    return Album(
      userId: json['userId'],
      id: json['id'],
      title: json['title'],
    );
  }
}

这个示例展示了一个完整的 Flutter 应用程序,它使用 Instana agent 来监控性能,并提供了详细的注释来帮助理解每个部分的功能。


更多关于Flutter性能监控插件instana_agent的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter性能监控插件instana_agent的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


当然,关于Flutter性能监控插件instana_agent的使用,下面是一个基本的集成和配置示例。请注意,具体的实现和配置可能会根据instana_agent的版本和Flutter项目的具体需求有所不同。由于instana_agent是一个商业性能监控解决方案,实际使用时可能需要参考Instana的官方文档和API进行更详细的配置。

首先,确保你的Flutter项目已经设置好,并且你已经获得了Instana的必要配置信息(如Agent Key)。

1. 添加依赖

在你的pubspec.yaml文件中添加instana_agent依赖:

dependencies:
  flutter:
    sdk: flutter
  instana_agent: ^x.y.z  # 替换为实际的版本号

然后运行flutter pub get来安装依赖。

2. 初始化Instana Agent

在你的应用的主入口文件(通常是main.dart)中初始化Instana Agent。

import 'package:flutter/material.dart';
import 'package:instana_agent/instana_agent.dart';

void main() {
  // 替换为你的Agent Key
  const String agentKey = 'your-agent-key-here';

  // 初始化Instana Agent
  InstanaAgent.initialize(agentKey: agentKey);

  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(),
    );
  }
}

class MyHomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Flutter Instana Demo'),
      ),
      body: Center(
        child: Text('Hello, Instana!'),
      ),
    );
  }
}

3. 自定义监控(可选)

Instana Agent通常会自动收集性能数据,但你也可以根据需要自定义监控逻辑。例如,你可以标记特定的代码块以监控其执行时间。

import 'package:instana_agent/instana_agent.dart';

void someFunction() async {
  // 开始一个自定义监控块
  final span = InstanaAgent.tracer.startActiveSpan('someFunction');

  try {
    // 模拟一些工作
    await Future.delayed(Duration(seconds: 2));
  } finally {
    // 结束监控块
    span?.finish();
  }
}

在上面的例子中,someFunction被标记为一个自定义的监控块,Instana将收集并报告这个块的执行时间。

4. 配置(可选)

Instana Agent可能允许你通过配置来调整其行为。这通常涉及到设置环境变量或传递配置对象。具体的配置选项需要参考Instana的官方文档。

注意事项

  • 确保你的Instana Agent Key是有效的,并且你的Instana服务正在运行。
  • 由于instana_agent是一个第三方库,其行为可能会随着版本的更新而变化。始终参考最新的官方文档。
  • 性能监控可能会引入额外的开销,特别是在高频率或复杂的监控场景下。在生产环境中使用时,请确保进行了充分的测试。

这个示例提供了一个基本的集成框架,但实际应用中可能需要根据具体需求进行更详细的配置和自定义。

回到顶部