Flutter日志分析与记录插件analytics_logger_gen的使用

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

Flutter日志分析与记录插件analytics_logger_gen的使用

analytics_logger_gen 是一个代码生成器,用于为工具(如 Firebase Analytics)生成分析事件。它可以从 Google 表格、远程仓库或本地 CSV 文件中导入事件。

运行生成器

要运行生成器,请执行以下命令:

dart pub run build_runner build

其他有用的命令:

dart pub run build_runner build --delete-conflicting-outputs
# 如果你想在构建之前删除生成的文件

dart pub run build_runner clean
# 如果修改了 CSV 文件后生成的文件未更新

调用生成的代码

你可以在项目中的任何地方调用生成的代码,这些方法返回 Future 类型。

await EventProvider.setup();

EventProvider.appStarted(title: 'Hello', message: 'world');

基于注解的代码生成

生成器会在找到带有 [@AnalyticsLogger](/user/AnalyticsLogger) 注解的成员时生成代码。

import 'package:analytics_logger_gen/analytics_logger_gen.dart';

// 生成对应的 part 'analytics_logger.g.dart'
part 'analytics_logger.g.dart';

[@AnalyticsLogger](/user/AnalyticsLogger)(
    // 例如:(从项目根目录)assets/logger_gen_example_sheet.csv
    localCsvPath: '<PATH-TO-CSV-FILE>',
    // 当声明了 localCsvPath 时,remoteCsvUrl 将被忽略。
    remoteCsvUrl: '<URL-TO-CSV-FILE>',
    
    loggers: <Type, String>{
      // Map 的键是实现 [EventLogger] 接口的类的类型。
      //
      // 在 [@AnalyticsLogger](/user/AnalyticsLogger) 中匹配 <CSV-COLUMN-NAME> 与 CSV 列以确定生成的事件应调用哪个分析工具。
      FirebaseAnalyticsLogger: '<CSV-COLUMN-NAME>',
    })
// 类应声明为私有 '_' 以避免与生成的类冲突
// ignore: unused_element
class _EventLoggerContainer {}

// 你可以声明任意数量的第三方分析工具的日志记录器。
class FirebaseAnalyticsLogger extends EventLogger {
  FirebaseAnalyticsLogger();

  final FirebaseAnalytics _analytics = FirebaseAnalytics.instance;

  [@override](/user/override)
  Future<void> setup() async {
    await Firebase.initializeApp();
    super.setup();
  }

  [@override](/user/override)
  Future<void> logEvent(String event,
      {required Map<String, dynamic> attributes}) async {
    switch (EventType.fromName(event)) {
      case EventType.setUserId:
        await _analytics.setUserId(
            id: attributes.values.first?.value.toString());
        break;
      case EventType.setUserInfo:
        for (final entry in attributes.entries) {
          await _analytics.setUserProperty(
            name: entry.key,
            value: entry.value,
          );
        }
        break;
      default:
        await _analytics.logEvent(name: event, parameters: attributes);
    }
  }
}

示例

调用生成的代码
EventProvider.appStarted();

EventProvider.buttonClicked(abTestCase: 'A');

EventProvider.purchase(productId: 'product-id', price: 100, currency: 'USD', quantity: 1);
CSV 文件
  • event_namearguments 列的索引不能修改;它们分别固定在第 0 和第 1 列。(你可以更改它们的名称,但不能更改索引。)
  • 你可以在 arguments 列的右侧添加任意数量的列。
  • [@AnalyticsLogger](/user/AnalyticsLogger)loggers 属性值中匹配的列将确定生成的事件应调用哪个分析工具。
  • 使用 [TRUE]/[1] 启用日志记录器,使用 [FALSE]/[0]/[ ] 禁用。
event_name arguments isFirebaseEnabled isAppsFlyerEnabled isAmplitudeEnabled isMixpanelEnabled isSingularEnabled isDatadogEnabled description
app_started title, message TRUE TRUE TRUE TRUE TRUE TRUE
home_page_entered ab_test_case TRUE TRUE TRUE TRUE TRUE
app_ended TRUE TRUE TRUE TRUE TRUE
button_clicked ab_test_case TRUE TRUE TRUE TRUE TRUE TRUE
select_contents content_type, item_id TRUE
send_message title, message TRUE TRUE TRUE TRUE
banner_clicked TRUE TRUE TRUE TRUE TRUE TRUE
set_user_id id TRUE
set_user_info age, gender TRUE
purchase productId, price, currency, quantity TRUE
生成代码的前提条件
本地 CSV 文件
import 'package:analytics_logger_gen/analytics_logger_gen.dart';

import '../event_logger_impls/event_loggers.dart';

part 'logger_from_local_file.g.dart';

[@AnalyticsLogger](/user/AnalyticsLogger)(
    localCsvPath: 'assets/logger_gen_example_v3.csv',
    loggers: {
      FirebaseAnalyticsLogger: 'isFirebaseEnabled',
      AppsFlyerLogger: 'isAppsFlyerEnabled',
      AmplitudeLogger: 'isAmplitudeEnabled',
      MixpanelLogger: 'isMixpanelEnabled',
      SingularLogger: 'isSingularEnabled',
      DatadogDebugLogger: 'isDatadogEnabled',
    },
    providerName: 'EventProvider',
    eventTypeName: 'EventType')
// ignore: unused_element
class _EventLoggerContainer {}
远程 CSV 文件
import 'package:analytics_logger_gen/analytics_logger_gen.dart';

import '../event_logger_impls/event_loggers.dart';

part 'logger_from_google_spread_sheet.g.dart';

[@AnalyticsLogger](/user/AnalyticsLogger)(
    remoteCsvUrl:
    'https://docs.google.com/spreadsheets/d/e/2PACX-1vSziB4YXy4C777tDDHlW96iT-640jWsfpc0cJLCc114DWxNusSQs61EkrY5lhLcp0T1Wkj1IJWijQ-j/pub?gid=0&single=true&output=csv',
    loggers: {
      FirebaseAnalyticsLogger: 'isFirebaseEnabled',
      AppsFlyerLogger: 'isAppsFlyerEnabled',
      AmplitudeLogger: 'isAmplitudeEnabled',
      MixpanelLogger: 'isMixpanelEnabled',
      SingularLogger: 'isSingularEnabled',
      DatadogDebugLogger: 'isDatadogEnabled',
    },
    providerName: 'EventProvider',
    eventTypeName: 'EventType')
// ignore: unused_element
class _EventLoggerContainer {}

class FirebaseAnalyticsLogger extends EventLogger {
  FirebaseAnalyticsLogger();

  [@override](/user/override)
  Future<void> logEvent(String event,
      {required Map<String, dynamic> attributes}) async {
    // Do something with the event and attributes
  }
}

class AppsFlyerLogger extends EventLogger {
  AppsFlyerLogger();

  [@override](/user/override)
  Future<void> logEvent(String event,
      {required Map<String, dynamic> attributes}) async {
    // Do something with the event and attributes
  }
}

class AmplitudeLogger extends EventLogger {
  AmplitudeLogger();

  [@override](/user/override)
  Future<void> logEvent(String event,
      {required Map<String, dynamic> attributes}) {
    // Do something with the event and attributes
  }
}

class MixpanelLogger extends EventLogger {
  MixpanelLogger();

  [@override](/user/override)
  Future<void> logEvent(String event,
      {required Map<String, dynamic> attributes}) async {
    // Do something with the event and attributes
  }
}

class SingularLogger extends EventLogger {
  SingularLogger();

  [@override](/user/override)
  Future<void> logEvent(String event,
      {required Map<String, dynamic> attributes}) async {
    // Do something with the event and attributes
  }
}

class DatadogDebugLogger extends EventLogger {
  DatadogDebugLogger();

  [@override](/user/override)
  Future<void> logEvent(String event,
      {required Map<String, dynamic> attributes}) async {
    // Do something with the event and attributes
  }
}

生成的代码

// GENERATED CODE - DO NOT MODIFY BY HAND

part of 'main.dart';

// **************************************************************************
// AnalyticsLoggerGenerator
// **************************************************************************

enum EventType {
  appStarted('app_started', true, true, true, true, true, true),
  homePageEntered('home_page_entered', true, true, true, true, false, true),
  appEnded('app_ended', true, true, true, true, true, false),
  buttonClicked('button_clicked', true, true, true, true, true, true),
  selectContents('select_contents', true, false, false, false, false, false),
  sendMessage('send_message', false, true, true, true, false, true),
  countIncreased('countIncreased', true, true, true, true, true, true),
  bannerClicked('banner_clicked', true, true, true, true, true, true),
  setUserId('set_user_id', true, false, false, false, false, false),
  setUserInfo('set_user_info', true, false, false, false, false, false),
  purchase('purchase', true, false, false, false, false, false);

  const EventType(
      this.name,
      this.isFirebaseEnabled,
      this.isAppsFlyerEnabled,
      this.isAmplitudeEnabled,
      this.isMixpanelEnabled,
      this.isSingularEnabled,
      this.isDatadogEnabled);
  final String name;
  final bool isFirebaseEnabled;
  final bool isAppsFlyerEnabled;
  final bool isAmplitudeEnabled;
  final bool isMixpanelEnabled;
  final bool isSingularEnabled;
  final bool isDatadogEnabled;

  static EventType fromName(String name) {
    switch (name) {
      case 'app_started':
        return EventType.appStarted;
      case 'home_page_entered':
        return EventType.homePageEntered;
      case 'app_ended':
        return EventType.appEnded;
      case 'button_clicked':
        return EventType.buttonClicked;
      case 'select_contents':
        return EventType.selectContents;
      case 'send_message':
        return EventType.sendMessage;
      case 'countIncreased':
        return EventType.countIncreased;
      case 'banner_clicked':
        return EventType.bannerClicked;
      case 'set_user_id':
        return EventType.setUserId;
      case 'set_user_info':
        return EventType.setUserInfo;
      case 'purchase':
        return EventType.purchase;
      default:
        throw ArgumentError('Invalid name: $name');
    }
  }
}

class EventProvider {
  EventProvider._();

  static Future<void> appStarted({dynamic title, dynamic message}) async {
    Map<String, dynamic> attributes = <String, dynamic>{
      'title': title,
      'message': message,
    };
    await EventLoggerContainer.logEvent(EventType.appStarted, attributes);
  }

  static Future<void> homePageEntered({dynamic abTestCase}) async {
    Map<String, dynamic> attributes = <String, dynamic>{
      'abTestCase': abTestCase,
    };
    await EventLoggerContainer.logEvent(EventType.homePageEntered, attributes);
  }

  static Future<void> appEnded() async {
    Map<String, dynamic> attributes = <String, dynamic>{};
    await EventLoggerContainer.logEvent(EventType.appEnded, attributes);
  }

  static Future<void> buttonClicked({dynamic abTestCase}) async {
    Map<String, dynamic> attributes = <String, dynamic>{
      'abTestCase': abTestCase,
    };
    await EventLoggerContainer.logEvent(EventType.buttonClicked, attributes);
  }

  static Future<void> selectContents(
      {dynamic contentType, dynamic itemId}) async {
    Map<String, dynamic> attributes = <String, dynamic>{
      'contentType': contentType,
      'itemId': itemId,
    };
    await EventLoggerContainer.logEvent(EventType.selectContents, attributes);
  }

  static Future<void> sendMessage({dynamic title, dynamic message}) async {
    Map<String, dynamic> attributes = <String, dynamic>{
      'title': title,
      'message': message,
    };
    await EventLoggerContainer.logEvent(EventType.sendMessage, attributes);
  }

  static Future<void> countIncreased({dynamic count}) async {
    Map<String, dynamic> attributes = <String, dynamic>{
      'count': count,
    };
    await EventLoggerContainer.logEvent(EventType.countIncreased, attributes);
  }

  static Future<void> bannerClicked() async {
    Map<String, dynamic> attributes = <String, dynamic>{};
    await EventLoggerContainer.logEvent(EventType.bannerClicked, attributes);
  }

  static Future<void> setUserId({dynamic id}) async {
    Map<String, dynamic> attributes = <String, dynamic>{
      'id': id,
    };
    await EventLoggerContainer.logEvent(EventType.setUserId, attributes);
  }

  static Future<void> setUserInfo({dynamic age, dynamic gender}) async {
    Map<String, dynamic> attributes = <String, dynamic>{
      'age': age,
      'gender': gender,
    };
    await EventLoggerContainer.logEvent(EventType.setUserInfo, attributes);
  }

  static Future<void> purchase(
      {dynamic productId,
        dynamic price,
        dynamic currency,
        dynamic quantity}) async {
    Map<String, dynamic> attributes = <String, dynamic>{
      'productId': productId,
      'price': price,
      'currency': currency,
      'quantity': quantity,
    };
    await EventLoggerContainer.logEvent(EventType.purchase, attributes);
  }
}

class EventLoggerContainer {
  EventLoggerContainer._();
  static FirebaseAnalyticsLogger firebaseAnalyticsLogger =
  FirebaseAnalyticsLogger();
  static AppsFlyerLogger appsFlyerLogger = AppsFlyerLogger();
  static AmplitudeLogger amplitudeLogger = AmplitudeLogger();
  static MixpanelLogger mixpanelLogger = MixpanelLogger();
  static SingularLogger singularLogger = SingularLogger();
  static DatadogDebugLogger datadogDebugLogger = DatadogDebugLogger();

  static Future<void> setup() async {
    await firebaseAnalyticsLogger.setup();
    await appsFlyerLogger.setup();
    await amplitudeLogger.setup();
    await mixpanelLogger.setup();
    await singularLogger.setup();
    await datadogDebugLogger.setup();
  }

  static Future<void> logEvent(
      EventType event, Map<String, dynamic> attributes) async {
    if (event.isFirebaseEnabled) {
      await firebaseAnalyticsLogger.logEvent(event.name,
          attributes: attributes);
    }
    if (event.isAppsFlyerEnabled) {
      await appsFlyerLogger.logEvent(event.name, attributes: attributes);
    }
    if (event.isAmplitudeEnabled) {
      await amplitudeLogger.logEvent(event.name, attributes: attributes);
    }
    if (event.isMixpanelEnabled) {
      await mixpanelLogger.logEvent(event.name, attributes: attributes);
    }
    if (event.isSingularEnabled) {
      await singularLogger.logEvent(event.name, attributes: attributes);
    }
    if (event.isDatadogEnabled) {
      await datadogDebugLogger.logEvent(event.name, attributes: attributes);
    }
  }
}

完整示例 Demo

以下是一个完整的示例应用程序,展示了如何使用 analytics_logger_gen 插件来记录和分析日志。

// ignore: depend_on_referenced_packages
import 'package:analytics_logger_gen/analytics_logger_gen.dart';

// ignore: depend_on_referenced_packages
import 'package:flutter/material.dart';

import '../event_logger_impls/event_loggers.dart';

part 'main.g.dart';

[@AnalyticsLogger](/user/AnalyticsLogger)(
    localCsvPath: 'assets/logger_gen_example_v3.csv',
    loggers: <Type, String>{
      FirebaseAnalyticsLogger: 'isFirebaseEnabled',
      AppsFlyerLogger: 'isAppsFlyerEnabled',
      AmplitudeLogger: 'isAmplitudeEnabled',
      MixpanelLogger: 'isMixpanelEnabled',
      SingularLogger: 'isSingularEnabled',
      DatadogDebugLogger: 'isDatadogEnabled',
    },
    providerName: 'EventProvider',
    eventTypeName: 'EventType')
// ignore: unused_element
class _EventLoggerContainer {}

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

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  [@override](/user/override)
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: const MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  const MyHomePage({super.key, required this.title});

  final String title;

  [@override](/user/override)
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  int _counter = 0;

  void _incrementCounter() {
    setState(() {
      _counter++;
    });
    EventProvider.countIncreased(count: _counter);
  }

  [@override](/user/override)
  void initState() {
    super.initState();

    WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
      _asyncMethod();
    });
  }

  _asyncMethod() async {
    // 初始化所有事件记录器
    await EventLoggerContainer.setup();

    // 或者单独初始化每个事件记录器
    await EventLoggerContainer.firebaseAnalyticsLogger.setup();

    EventProvider.appStarted();
  }

  [@override](/user/override)
  void dispose() {
    EventProvider.appEnded();
    super.dispose();
  }

  [@override](/user/override)
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            const Text(
              'You have pushed the button this many times:',
            ),
            Text(
              '$_counter',
              style: Theme.of(context).textTheme.headlineMedium,
            ),
          ],
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: _incrementCounter,
        tooltip: 'Increment',
        child: const Icon(Icons.add),
      ),
    );
  }
}

更多关于Flutter日志分析与记录插件analytics_logger_gen的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter日志分析与记录插件analytics_logger_gen的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


当然,以下是如何在Flutter项目中使用analytics_logger_gen插件进行日志分析与记录的代码示例。analytics_logger_gen是一个假设的插件名称,用于说明目的,实际使用中请确保插件名称和用法符合真实插件的文档。

1. 添加依赖

首先,在你的pubspec.yaml文件中添加analytics_logger_gen依赖:

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

然后运行flutter pub get来获取依赖。

2. 初始化插件

在你的应用入口文件(通常是main.dart)中初始化插件:

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

void main() {
  // 初始化AnalyticsLogger
  final AnalyticsLogger logger = AnalyticsLogger(
    // 配置日志级别等参数
    level: LogLevel.verbose,
    output: Output.console, // 输出到控制台,实际使用中可能输出到文件或远程服务器
  );

  runApp(MyApp(logger: logger));
}

class MyApp extends StatelessWidget {
  final AnalyticsLogger logger;

  MyApp({required this.logger});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text('Flutter Analytics Logger Demo'),
        ),
        body: Center(
          child: LogExample(logger: logger),
        ),
      ),
    );
  }
}

3. 使用插件记录日志

在你的应用组件中使用插件记录不同类型的日志:

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

class LogExample extends StatelessWidget {
  final AnalyticsLogger logger;

  LogExample({required this.logger});

  @override
  Widget build(BuildContext context) {
    return Column(
      mainAxisAlignment: MainAxisAlignment.center,
      children: <Widget>[
        ElevatedButton(
          onPressed: () {
            logger.verbose('This is a verbose log message.');
            logger.debug('This is a debug log message.');
            logger.info('This is an info log message.');
            logger.warning('This is a warning log message.');
            logger.error('This is an error log message.');
          },
          child: Text('Log Messages'),
        ),
        ElevatedButton(
          onPressed: () {
            // 假设有一个自定义的日志事件
            logger.logCustomEvent(
              event: 'user_action',
              parameters: {
                'action': 'button_clicked',
                'timestamp': DateTime.now().toIso8601String(),
              },
            );
          },
          child: Text('Log Custom Event'),
        ),
      ],
    );
  }
}

4. 自定义日志输出(可选)

如果你需要将日志输出到文件或远程服务器,可以自定义输出方式。例如,输出到文件:

import 'dart:io';
import 'package:path_provider/path_provider.dart';
import 'package:analytics_logger_gen/analytics_logger_gen.dart';

class FileLoggerOutput implements LogOutput {
  final File _logFile;

  FileLoggerOutput() : _logFile = File('${(getApplicationDocumentsDirectory() as Future<Directory>).sync().path}/app.log');

  @override
  Future<void> writeLog(LogLevel level, String message) async {
    final String logEntry = '[${DateTime.now().toIso8601String()}] [$level] $message\n';
    await _logFile.writeAsString(logEntry, mode: FileMode.append);
  }
}

void main() async {
  final Directory appDocDir = await getApplicationDocumentsDirectory();
  final AnalyticsLogger logger = AnalyticsLogger(
    level: LogLevel.verbose,
    output: FileLoggerOutput(), // 使用自定义的文件输出
  );

  runApp(MyApp(logger: logger));
}

请注意,上述代码示例中的analytics_logger_gen插件及其API是假设的。在实际使用中,请查阅具体插件的官方文档以获取准确的API和用法。同时,确保处理任何潜在的异步操作(如文件IO)时,使用适当的错误处理和资源管理策略。

回到顶部