voo_telemetry 0.2.3 copy "voo_telemetry: ^0.2.3" to clipboard
voo_telemetry: ^0.2.3 copied to clipboard

OpenTelemetry integration for VooFlutter with support for traces, metrics, and logs.

example/lib/main.dart

import 'package:dio/dio.dart';
import 'package:flutter/material.dart';
import 'package:voo_telemetry/voo_telemetry.dart';

void main() async {
  WidgetsFlutterBinding.ensureInitialized();

  // Initialize VooTelemetry with your DevStack API endpoint
  await VooTelemetry.initialize(
    endpoint: 'http://localhost:5000', // Replace with your DevStack API URL
    apiKey: 'your-api-key', // Optional: Add your API key
    serviceName: 'voo-example-app',
    serviceVersion: '2.0.0',
    additionalAttributes: {'deployment.environment': 'development', 'app.platform': 'flutter'},
    debug: true,
  );

  runApp(const MyApp());
}

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

  @override
  Widget build(BuildContext context) => MaterialApp(
    title: 'VooTelemetry Demo',
    theme: ThemeData(colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple), useMaterial3: true),
    home: const TelemetryDemoPage(),
  );
}

class TelemetryDemoPage extends StatefulWidget {
  const TelemetryDemoPage({super.key});

  @override
  State<TelemetryDemoPage> createState() => _TelemetryDemoPageState();
}

class _TelemetryDemoPageState extends State<TelemetryDemoPage> {
  final _tracer = VooTelemetry.instance.getTracer('demo-app');
  final _meter = VooTelemetry.instance.getMeter('demo-metrics');
  final _logger = VooTelemetry.instance.getLogger('demo-logger');

  late final Counter _buttonClickCounter;
  late final Histogram _operationDuration;
  late final Gauge _activeUsers;

  int _clickCount = 0;
  String _status = 'Ready';

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

    // Initialize metrics instruments
    _buttonClickCounter = _meter.createCounter('button_clicks', description: 'Number of button clicks', unit: 'clicks');

    _operationDuration = _meter.createHistogram('operation_duration', description: 'Duration of operations', unit: 'ms');

    _activeUsers = _meter.createGauge('active_users', description: 'Number of active users');

    // Set initial gauge value
    _activeUsers.set(1);

    // Log app startup
    _logger.info('Application started', attributes: {'screen': 'TelemetryDemoPage', 'platform': Theme.of(context).platform.toString()});
  }

  Future<void> _performTracedOperation() async {
    setState(() => _status = 'Running traced operation...');

    try {
      await _tracer.withSpan('demo-operation', (span) async {
        span.setAttribute('user.action', 'button_click');
        span.setAttribute('click.count', _clickCount);

        // Simulate some work
        span.addEvent('Starting processing');
        await Future<void>.delayed(const Duration(milliseconds: 500));

        span.addEvent('Fetching data');
        await _fetchData(span);

        span.addEvent('Processing complete');

        setState(() => _status = 'Operation completed successfully');
      });
    } catch (e, stackTrace) {
      setState(() => _status = 'Operation failed: $e');
      _logger.error('Operation failed', error: e, stackTrace: stackTrace);
    }
  }

  Future<void> _fetchData(Span parentSpan) async {
    await _tracer.withSpan('fetch-data', (span) async {
      span.setAttribute('http.method', 'GET');
      span.setAttribute('http.url', 'https://jsonplaceholder.typicode.com/posts/1');

      final stopwatch = Stopwatch()..start();

      try {
        final dio = Dio();
        final response = await dio.get('https://jsonplaceholder.typicode.com/posts/1');

        span.setAttribute('http.status_code', response.statusCode);
        span.setAttribute('response.size', response.data.toString().length);

        _logger.info('Data fetched successfully', attributes: {'status_code': response.statusCode, 'data_size': response.data.toString().length});
      } finally {
        stopwatch.stop();
        _operationDuration.record(stopwatch.elapsedMilliseconds.toDouble(), attributes: {'operation': 'fetch_data'});
      }
    }, kind: SpanKind.client);
  }

  void _recordMetrics() {
    setState(() {
      _clickCount++;
      _status = 'Recording metrics...';
    });

    // Record counter metric
    _buttonClickCounter.increment(attributes: {'button': 'record_metrics', 'screen': 'demo'});

    // Record gauge metric
    _activeUsers.set(_clickCount.toDouble());

    // Log the action
    _logger.info('Metrics recorded', attributes: {'click_count': _clickCount, 'timestamp': DateTime.now().toIso8601String()});

    setState(() => _status = 'Metrics recorded: $_clickCount clicks');
  }

  void _simulateError() {
    setState(() => _status = 'Simulating error...');

    try {
      // This will throw an error
      throw Exception('Simulated error for demonstration');
    } catch (e, stackTrace) {
      // Record the exception
      VooTelemetry.instance.recordException(e, stackTrace, attributes: {'error.simulated': true, 'user.action': 'simulate_error_button'});

      setState(() => _status = 'Error recorded and sent');
    }
  }

  Future<void> _flushTelemetry() async {
    setState(() => _status = 'Flushing telemetry data...');

    await VooTelemetry.instance.flush();

    setState(() => _status = 'Telemetry data flushed');

    _logger.info('Manual flush completed', attributes: {'click_count': _clickCount});
  }

  @override
  Widget build(BuildContext context) => Scaffold(
    appBar: AppBar(backgroundColor: Theme.of(context).colorScheme.inversePrimary, title: const Text('VooTelemetry Demo')),
    body: Center(
      child: Padding(
        padding: const EdgeInsets.all(16.0),
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Text('OpenTelemetry Integration Demo', style: Theme.of(context).textTheme.headlineMedium),
            const SizedBox(height: 20),
            Text('Status: $_status', style: Theme.of(context).textTheme.bodyLarge),
            const SizedBox(height: 10),
            Text('Click count: $_clickCount', style: Theme.of(context).textTheme.bodyMedium),
            const SizedBox(height: 40),
            Wrap(
              spacing: 10,
              runSpacing: 10,
              alignment: WrapAlignment.center,
              children: [
                ElevatedButton.icon(onPressed: _performTracedOperation, icon: const Icon(Icons.play_arrow), label: const Text('Run Traced Operation')),
                ElevatedButton.icon(onPressed: _recordMetrics, icon: const Icon(Icons.analytics), label: const Text('Record Metrics')),
                ElevatedButton.icon(
                  onPressed: _simulateError,
                  icon: const Icon(Icons.error_outline),
                  label: const Text('Simulate Error'),
                  style: ElevatedButton.styleFrom(backgroundColor: Colors.orange),
                ),
                ElevatedButton.icon(
                  onPressed: _flushTelemetry,
                  icon: const Icon(Icons.cloud_upload),
                  label: const Text('Flush Telemetry'),
                  style: ElevatedButton.styleFrom(backgroundColor: Colors.green),
                ),
              ],
            ),
            const SizedBox(height: 40),
            Card(
              child: Padding(
                padding: const EdgeInsets.all(16.0),
                child: Column(
                  children: [
                    Text('Telemetry Types Demonstrated:', style: Theme.of(context).textTheme.titleMedium),
                    const SizedBox(height: 10),
                    const Text('✅ Distributed Tracing (Spans)'),
                    const Text('✅ Metrics (Counter, Histogram, Gauge)'),
                    const Text('✅ Structured Logging'),
                    const Text('✅ Exception Tracking'),
                    const Text('✅ Context Propagation'),
                  ],
                ),
              ),
            ),
          ],
        ),
      ),
    ),
    floatingActionButton: FloatingActionButton(
      onPressed: () {
        // Navigate to settings or info page
        showDialog(
          context: context,
          builder: (context) => AlertDialog(
            title: const Text('VooTelemetry Info'),
            content: const Text(
              'This demo app showcases the VooTelemetry package '
              'integration with OpenTelemetry.\n\n'
              'All telemetry data is sent to your configured '
              'DevStack API endpoint for processing and visualization.',
            ),
            actions: [TextButton(onPressed: () => Navigator.of(context).pop(), child: const Text('OK'))],
          ),
        );
      },
      tooltip: 'Info',
      child: const Icon(Icons.info_outline),
    ),
  );

  @override
  void dispose() {
    _logger.info('Application closing', attributes: {'total_clicks': _clickCount});
    super.dispose();
  }
}
1
likes
140
points
254
downloads

Publisher

verified publishervoostack.com

Weekly Downloads

OpenTelemetry integration for VooFlutter with support for traces, metrics, and logs.

Homepage
Repository (GitHub)
View/report issues

Topics

#flutter #opentelemetry #observability #tracing #otlp

Documentation

API reference

License

MIT (license)

Dependencies

collection, dio, fixnum, flutter, http, path, path_provider, protobuf, sembast, sembast_web, synchronized, uuid, voo_core

More

Packages that depend on voo_telemetry