Flutter 개발 상자

[Flutter] Talker 패키지를 이용하여 로그(Log)를 파일로 저장하기 본문

Flutter

[Flutter] Talker 패키지를 이용하여 로그(Log)를 파일로 저장하기

망고상자 2023. 12. 21. 17:40
728x90

Talker 소개

 

 

패키지 소개

Talker pub.dev

WebDemo

 

Talker는 예전에 어떤분의 강의영상을 보면서 소개받은 로그 패키지인데

그냥 위의 로그프리뷰를 보고 한눈에 반해버렸다.

Logger패키지 이상으로 이쁜 로그, 간단한 사용법, 꾸준한 업데이트, 그리고 멋진 로그 모니터링 화면

이거 갈아타지 않을 이유가 없는데? 싶어서 바로 Talker 패키지를 사용하기로 마음 먹었다.

 

 

간단 사용법

Talker의 기본 사용법은 매우 간편하고 logger 패키지와 사용법이 비슷한편이다.

main 파일의 최상단 영역에 talker 전역변수를 설정하고 필요한 곳에서 호출해서 사용하면된다.

 

// 전역변수 선언
final Talker talker = Talker();

void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  ...
  
  // 로그 남기기
  talker.good('네트워크 통신 성공 !');
}

 

기본적으로 지원해주는 로그레벨 템블릿으로는

info

good

debug

error

등이 있다.

 

성공적인 결과를 보여주는 로그는 good,

에러내용을 보여주는 로그는 error

 

이런식으로 사용하면 좋을것같다.

 

 

 

로그를 파일로 저장하기

 

TalkerObserver 설정

Talker에서 출력해주는 텍스트를 파일로 저장해야하기에 Talker에서 로그를 찍어줄 때 마다 이를 수신할 수 있는 옵저버 클래스를 만들어주어야 한다.

 

class AppTalkerObserver extends TalkerObserver {
  @override
  void onLog(TalkerDataInterface log) {
    debugPrint('@@@ logLevel : ${log.logLevel}');
    debugPrint('@@@ logPrint : ${log.generateTextMessage()}');
  }
}

 

app_talker_observer.dart 파일을 만들고 위와같이 코드를 만들어준다.

onLog는 Talker가 로그를 생성할때마다 호출되는 메서드이다.

로그의 레벨(종류)와 전체 메시지를 호출하는 generateTextMessage를 프린트하도록 했다.

 

final talker = Talker(
  observer: AppTalkerObserver(),
);

...

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

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            ElevatedButton(
              onPressed: () {
                talker.error('냥냥');
              },
              child: Text(
                '로그출력 버튼',
              ),
            ),
          ],
        ),
      ),
    );
  }
}

 

아까 메인에 생성한 Talker 클래스에 observer 파라미터를 추가하여 아까 생성한 옵저버 클래스를 넣어준 후, 테스트를 위해 간단한 버튼 위젯을 만들었다.

 

버튼을 누를경우

 

 

위와 같은 로그창을 볼 수 있게된다.

 

로그 레벨을 통해 필요한 로그 타입만 골라서 분기처리를 하는것이 가능할것이며,

generateTextMessage를 통해서 로그 내용을 기록하는것이 가능할 것같다.

 

 

로그파일 생성 및 입력

이제 로그를 파일로 남겨보자.

플러터는 따로 패키지 추가를 할 필요 없이 파일 I/O 작업이 가능하지만 파일을 저장할 경로를 정해주는건 패키지를 사용하는것이 손쉽다.

 

따라서 아래의 패키지를 임포트 하고 시작하자.

path_provider: ^2.1.1

 

 

 

로직에 대해서 설명하자면

앱 내부 캐시 폴더에 로그 파일을 생성하고 로그를 기록해준뒤 로그 출력 버튼을 만들어 로그 기록을 확인할 수 있게 할것이다.

 

import 'dart:io';

import 'package:path_provider/path_provider.dart';
import 'package:talker/talker.dart';

class AppTalkerObserver extends TalkerObserver {
  // 싱글톤 적용
  AppTalkerObserver._privateConstructor();

  static final AppTalkerObserver _instance = AppTalkerObserver._privateConstructor();

  factory AppTalkerObserver() => _instance;

  File? _file;

  String readTxtFile() {
    if (_file?.existsSync() ?? false) {
      // 파일이 존재하면 내용을 읽어와서 출력
      String content = _file!.readAsStringSync();
      return content;
    } else {
      return 'File not found';
    }
  }

  @override
  void onLog(TalkerDataInterface log) async {
    // 파일이 없다면 앱 캐시 폴더 경로에 log.txt 파일을 생성함.
    _file ??= File('${(await getTemporaryDirectory()).path}/log.txt');

    // 로그 메시지를 파일에 기록한다.
    _file?.writeAsStringSync(
      '${log.generateTextMessage()}\n',
      mode: FileMode.writeOnlyAppend, // 파일에 이미 내용이 있을 경우 그 뒤에 덧붙여서 기록하는 모드
    );
  }
}

 

아까 만든 옵저버 클래스를 싱글톤패턴으로 만들고,

로그가 출력될때 마다 파일에 기록하고, 한줄 개행을 해준다.

또한 readTxtFile 이라는 메서드를 만들어서 로그파일의 String을 읽을 수 있도록 해준다.

 

import 'package:flutter/material.dart';
import 'package:taker_sample/app_talker_observer.dart';
import 'package:talker/talker.dart';

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

final talker = Talker(
  observer: AppTalkerObserver(),
);

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

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
        useMaterial3: true,
      ),
      home: const HomePage(),
    );
  }
}

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

  @override
  State<HomePage> createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> {
  final TextEditingController logTextController = TextEditingController();

  @override
  void dispose() {
    logTextController.dispose();
    super.dispose();
  }
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            Row(
              mainAxisAlignment: MainAxisAlignment.spaceAround,
              children: [
                ElevatedButton(
                  onPressed: () => talker.good('원신'),
                  child: const Text('Good'),
                ),
                ElevatedButton(
                  onPressed: () => talker.debug('블아'),
                  child: const Text('Debug'),
                ),
                ElevatedButton(
                  onPressed: () => talker.error('니케'),
                  child: const Text('Error'),
                ),
              ],
            ),
            const SizedBox(height: 20),
            ElevatedButton(
              onPressed: () {
                final String logText = AppTalkerObserver().readTxtFile();
                logTextController.text = logText;
              },
              child: const Text('기록된 로그 확인'),
            ),
            const SizedBox(height: 10),
            Padding(
              padding: const EdgeInsets.symmetric(horizontal: 10),
              child: TextField(
                readOnly: true,
                minLines: 10,
                maxLines: 10,
                controller: logTextController,
              ),
            ),
          ],
        ),
      ),
    );
  }
}

 

메인에서 로그를 생성하고 출력할 수 있는 UI를 구성하였다.

위의 코드를 통해서 만든 UI는 아래와 같다.

 

 

로그가 파일에 잘 입출력되고 있는것을 확인할 수 있다.

 

 

사실 Talker 패키지에서는 TalkerScreen 이라는 화면을 제공해주며, 여기서 로그의 저장을 손쉽게 할 수 있다.

그러나 이는 디버깅의 영역이 강하고, 사용자의 행동을 로그로 자동으로 기록하는건 위와같이 옵저버 클래스를 커스텀하여 기록해주어야 한다.

 

그리고 이는 사실 logger 패키지로도 가능하다.

LogOutput 클래스를 상속받은 커스텀 클래스를 구성해주고 logger의 output 파라미터에 붙여주면 동일하게 구현 가능하다.

 

요약

  • Talker 패키지의 Observer 파라미터를 통해서 로그가 출력될때마다 파일에 로그를 저장할 수 있다.
728x90