Flutter: How to show log output in console and automatically store it?

Viewed 2340

I am gradually understanding logging packages for Flutter. The easiest thing to do is to show in the console the different log messages by level but I'd also want to store the log outputs into a file, in order to be able to handle the information later. I'm wondering if someone in the community has already done something similar and would like to share an explanation or concrete implementation of this.

1 Answers

Having done more research and reading the documentation of logger package I'd like to share my code in case anybody in the community in the future needs to do something similar. This outputs the log messages in the console and automatically stores them in a .txt at a local place from your device as the image can show.

enter image description here

import 'package:flutter/material.dart';
import 'package:logger/logger.dart';
import 'dart:convert';
import 'dart:io';
import 'package:path_provider/path_provider.dart';
import 'package:logger/src/logger.dart';
import 'package:logger/src/log_output.dart';
import 'dart:io' as io;

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

class MyApp extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
        visualDensity: VisualDensity.adaptivePlatformDensity,
      ),
      home: MyLogger(),
    );
  }
}

class MyLogger extends StatefulWidget {
  @override
  _MyLoggerState createState() => _MyLoggerState();
}

class _MyLoggerState extends State<MyLogger> {
  File file;
  Logger logger;

  @override
  void initState() {
    getDirectoryForLogRecord().whenComplete(
      () {
        FileOutput fileOutPut = FileOutput(file: file);
        ConsoleOutput consoleOutput = ConsoleOutput();
        List<LogOutput> multiOutput = [fileOutPut, consoleOutput];
        logger = Logger(
            filter: DevelopmentFilter(),
            // Use the default LogFilter (-> only log in debug mode)
            printer: PrettyPrinter(
                methodCount: 2,
                // number of method calls to be displayed
                errorMethodCount: 8,
                // number of method calls if stacktrace is provided
                lineLength: 120,
                // width of the output
                colors: true,
                // Colorful log messages
                printEmojis: false,
                // Print an emoji for each log message
                printTime: true // Should each log print contain a timestamp
                ),
            // Use the PrettyPrinter to format and print log
            output:
                MultiOutput(multiOutput) // Use the default LogOutput (-> send everything to console)
            );
      },
    );
    // TODO: implement initState
    super.initState();
  }

  Future<void> getDirectoryForLogRecord() async {
    final Directory directory = await getApplicationDocumentsDirectory();
    file = File('${directory.path}/withMultiOutput.txt');
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
        child: FlatButton(
          onPressed: () {
            print("you pressed it");
            logger.v("Verbose log");

            logger.d("Debug log");

            logger.i("Info log");

            logger.w("Warning log");

            logger.e("Error log");

            logger.wtf("What a terrible failure log");
          },
          height: 60,
          minWidth: 120,
          color: Colors.blue,
          child: Text(
            'TEST WITH BOTH',
            style: TextStyle(color: Colors.white),
          ),
        ),
      ),
    );
  }
}

/// Writes the log output to a file.
class FileOutput extends LogOutput {
  final File file;
  final bool overrideExisting;
  final Encoding encoding;
  IOSink _sink;

  // IOSink? _sink;

  FileOutput({
    @required this.file,
    this.overrideExisting = false,
    this.encoding = utf8,
  });

  @override
  void init() {
    _sink = file.openWrite(
      mode: overrideExisting ? FileMode.writeOnly : FileMode.writeOnlyAppend,
      encoding: encoding,
    );
  }

  @override
  void output(OutputEvent event) {
    _sink?.writeAll(event.lines, '\n');
  }

  @override
  void destroy() async {
    await _sink?.flush();
    await _sink?.close();
  }
}
Related