Flutter性能监控插件instana_agent的使用
Flutter性能监控插件instana_agent的使用
Instana agent for Flutter
Instana agent 使 Flutter 应用程序能够将监控数据发送到 Instana。
Requirements
- Flutter 版本 1.20.0 及以上
- Dart 版本介于 2.12.0 和 4.0.0 之间
Installation
Instana agent Flutter 包可通过 pub.dev 获取。
您可以像往常一样将其添加到应用程序中:
- 打开
pubspec.yaml
文件(位于应用文件夹内),并在dependencies
下添加instana_agent:
- 安装它
- 从终端:运行
flutter pub get
- 或者:
- 从 Android Studio/IntelliJ:点击
pubspec.yaml
顶部操作带中的 Packages get - 从 VS Code:点击
pubspec.yaml
顶部操作带右侧的 Get Packages
- 从 Android Studio/IntelliJ:点击
- 从终端:运行
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 平台,还需做以下两个更改:
- 在项目级别的 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"
}
}
- 在 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
更多关于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
是一个第三方库,其行为可能会随着版本的更新而变化。始终参考最新的官方文档。 - 性能监控可能会引入额外的开销,特别是在高频率或复杂的监控场景下。在生产环境中使用时,请确保进行了充分的测试。
这个示例提供了一个基本的集成框架,但实际应用中可能需要根据具体需求进行更详细的配置和自定义。