Notice
Recent Posts
Recent Comments
Link
| 일 | 월 | 화 | 수 | 목 | 금 | 토 |
|---|---|---|---|---|---|---|
| 1 | 2 | 3 | 4 | 5 | ||
| 6 | 7 | 8 | 9 | 10 | 11 | 12 |
| 13 | 14 | 15 | 16 | 17 | 18 | 19 |
| 20 | 21 | 22 | 23 | 24 | 25 | 26 |
| 27 | 28 | 29 | 30 |
Tags
- 알고리즘
- Di
- Match
- Jira Slack 연동
- pub workspace go_router
- 멀티패키지
- 멀티모듈 고 라우터
- flutter interceptor
- 스위프트
- Swift
- 펍 워크스페이스
- 네트워크
- Flutter
- Bitbucket Slack 연동
- 단편화
- Algorithm
- 플러터
- Flutter Network Interceptor
- Python
- 플러터 인터셉터
- 난수
- go_router
- 고 라우터
- ci/cd
- 패킷
- Flutter Logging
- Flutter Netwrok Logging
- ios
- IP
- 인터셉터 구현
Archives
- Today
- Total
INEEDACHACHA
Flutter Network Logging Interceptor 본문
구현된 구조
25.07.23 수정 사항
- print -> developer.log로 최종 변경 (DevTools에 최적화)
- VScode는 Terminal에서 안 보이나 DevTools에서는 상세히 보임
- Android Studio에서는 developer.log가 Console에서 보임
- developer로그로 변경한 이유
- DevTools에 최적화
- Tag, Level 등을 공식 기능으로 설정 가능
- DevTools에 최적화
1. NetworkLoggable 인터페이스
abstract class NetworkLoggable {
void info(NetworkLog log);
void error(NetworkLog log);
}
class ConsoleLogger implements NetworkLoggable {
@override
void info(NetworkLog log) => developer.log(log.toString(), name: 'NetworkLog');
@override
void error(NetworkLog log) => developer.log(log.toString(), name: 'NetworkLog');
}
주요 특징:
- 로깅 동작을 추상화
- 다양한 로거 구현체를 만들 수 있도록 정의
2. NetworkLog 데이터 모델
enum NetworkLogType {
willSend,
didReceive,
}
class NetworkLog {
final String id;
final NetworkLogType type;
final String method;
final String baseUrl;
final String path;
final Map<String, dynamic>? headers;
final String? body;
final int? statusCode;
final String? response;
final DateTime loggedAt;
NetworkLog({
required this.type,
required this.method,
required this.baseUrl,
required this.path,
this.headers,
this.body,
this.statusCode,
this.response,
}) : id = const Uuid().v4().toString(),
loggedAt = DateTime.now();
}
@override
String toString() {
switch (type) {
case NetworkLogType.willSend:
return '''
⚡️ ━━━━━━━━━━━━━━━ 네트워크 요청 경로: $path ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
[REQUEST DATE]: $loggedAt
[HTTP METHOD]: $method
[BASE URL]: $baseUrl
[BODY]: ${body ?? "EMPTY BODY"}
''';
case NetworkLogType.didReceive:
return '''
🌐 ━━━━━━━━━━━━━━━ 네트워크 응답 경로: $path ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
[RESPONSE DATE]: $loggedAt
[HTTP METHOD]: $method
[STATUS CODE]: ${statusCode ?? "UNKNOWN"}
[BASE URL]: $baseUrl
[RESPONSE]: ${response ?? "EMPTY RESPONSE"}
''';
}
}
}
주요 특징:
- UUID로 각 로그에 고유 ID 부여
- 요청/응답 시점 자동 기록
3. NetworkLogInterceptor 구현
class NetworkLogInterceptor extends Interceptor {
final NetworkLoggable logger;
NetworkLogInterceptor({required this.logger});
@override
void onRequest(RequestOptions options, RequestInterceptorHandler handler) {
logger.info(
NetworkLog(
type: NetworkLogType.willSend,
method: options.method,
path: options.path,
baseUrl: options.baseUrl,
headers: options.headers,
body: options.data,
),
);
handler.next(options);
}
@override
void onResponse(Response response, ResponseInterceptorHandler handler) {
logger.info(
NetworkLog(
type: NetworkLogType.didReceive,
method: response.requestOptions.method,
path: response.requestOptions.path,
baseUrl: response.requestOptions.baseUrl,
headers: response.requestOptions.headers,
body: response.requestOptions.data,
statusCode: response.statusCode,
response: prettyJson(response.data),
),
);
handler.next(response);
}
@override
void onError(DioException err, ErrorInterceptorHandler handler) {
final descriptor = NetworkErrorDescriptor(err);
logger.error(
NetworkLog(
type: NetworkLogType.didReceive,
method: err.requestOptions.method,
path: err.requestOptions.path,
baseUrl: err.requestOptions.baseUrl,
headers: err.requestOptions.headers,
response: descriptor.errorLogMessage(),
),
);
handler.next(err);
}
}
주요 특징:
- Dio 인터셉터를 확장하여 네트워크 라이프사이클 센싱
- 요청 전(
onRequest), 응답 후(onResponse), 에러 발생시(onError) 로깅 - 의존성 주입을 통한 유연한 로거 교체 가능
4. DioFactory 통합
@LazySingleton(as: DioFactory)
class DioFactoryImpl implements DioFactory {
@override
Dio create(String baseUrl) {
final dio = Dio(BaseOptions(baseUrl: baseUrl));
dio.interceptors.add(NetworkLogInterceptor(logger: ConsoleLogger()));
return dio;
}
}
주요 특징:
- 모든 Dio 인스턴스에 로깅 인터셉터 자동 추가
로그 출력 예시
요청 로그
⚡️ ━━━━━━━━━━━━━━━ 네트워크 요청 경로: $path ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
[REQUEST DATE]: $loggedAt
[HTTP METHOD]: $method
[BASE URL]: $baseUrl
[BODY]: ${body ?? "EMPTY BODY"}
응답 로그
🌐 ━━━━━━━━━━━━━━━ 네트워크 응답 경로: $path ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
[RESPONSE DATE]: $loggedAt
[HTTP METHOD]: $method
[STATUS CODE]: ${statusCode ?? "UNKNOWN"}
[BASE URL]: $baseUrl
[RESPONSE]: ${response ?? "EMPTY RESPONSE"}
DevTools


- 해당 작업물의 DevTools에서의 모습이다.
- 요청 당 한 개의 로그를 쓰고있다.
- 클릭 했을 시 디테일 출력이 깔끔하다.
확장성 및 개선 사항
개선 예정 사항
- 플러그인 주입 개선: 현재
DioFactory에 하드코딩된ConsoleLogger를 DI를 통해 주입 가능하도록 개선 예정 - Refresh 관련 Interceptor 추가: 토큰 갱신 관련 인터셉터 추가 예정
- 로그 레벨 설정: 개발/운영 환경에 따라 로그 레벨 조정 기능
Logger, Talker를 선택 안 한 이유
- DevtTools의 활용도가 커질 것을 예상했기 때문
- Native와 달리 DevTools가 상당히 잘 되어있고 디테일한 부분 까지 추적이 가능해보였다.


- Logger, Talker의 DevTool의 모습이다.
- 위와 같이 하나의 요청과 로그에 n개의 로그가 찍힌다.
- Detail을 클릭해도 자세한 내용이 한 눈에 보이기 보다는 n개로 나눠져있어 가독성이 좋지 않다.
'Flutter > 전환실록' 카테고리의 다른 글
| Flutter Project Atlassian Setting (0) | 2025.07.23 |
|---|---|
| Pub Workspace에서 go_router 기반 네비게이션 시스템 구현 (0) | 2025.07.15 |
| Flutter Pub Workspaces 구조 – 현재 프로젝트 기준 (1) | 2025.07.15 |
| Flutter Cocoapods -> SPM 전환 Trouble Shooting (6) | 2025.07.10 |
| Flutter Network Module => Swift Moya Style로 만들어보기 (0) | 2025.06.13 |