app_log_tracker 0.2.0
app_log_tracker: ^0.2.0 copied to clipboard
Event + API log tracker with dedup and offline outbox for Flutter.
app_log_tracker #
Event + API log tracker dengan dedup dan offline outbox untuk Flutter.
[Demo app] [Debug overlay]
Bukan cuma HTTP logger. Consumer bisa track event custom apapun
(errorApi, notif_read, ...), disimpan dulu di local,
di-dedup (keyEvent + id + data), lalu dikirim ke server sebagai
satu batch JSON dengan batch_id unik.
Cocok untuk: tracking error log, tracking user baca notifikasi multi-case, positive/negative case, dan API log otomatis (Dio + http).
Fitur #
track(keyEvent, id, status, data)— custom event apapun- Dedup otomatis: sama persis → skip, beda → tambah
- Auto API log:
TrackerDioInterceptor+TrackedHttpClient - Outbox: simpan di local dulu,
flush()/startAutoExport()kirim batch ke server deleteEvents(ids)buat hapus manual,clear()wajib saat logoutbatch_id(uuid) sebagai idempotency key per payload- Storage:
SqfliteTrackStorage(persist) +InMemoryTrackStorage(test) - Overlay debug: list, search, filter success/failed, detail JSON, clear
- Cap 500 event per device (FIFO), batch 50, timeout 15s, bedain 4xx vs 5xx
Install #
dependencies:
app_log_tracker: ^0.2.0
Usage #
1. Custom event + dedup #
import 'package:app_log_tracker/app_log_tracker.dart';
final tracker = LogTracker(storage: SqfliteTrackStorage());
final added = await tracker.track(
keyEvent: 'errorApi',
id: 'user_123',
status: TrackStatus.failed,
data: {'code': 'EMAIL_TAKEN'},
);
// added == false kalau keyEvent+id+data sudah ada -> di-skip
2. Auto API log (Dio + http) #
final dio = Dio()..interceptors.add(TrackerDioInterceptor(tracker));
final client = TrackedHttpClient(tracker, http.Client());
await client.get(Uri.parse('https://api.lu/users'));
3. Kirim ke server (outbox) #
Payload yang dikirim:
{
"batch_id": "uuid-v4",
"sent_at": "2026-10-03T10:00:00+07:00",
"events": [
{
"event_id": "uuid",
"key_event": "errorApi",
"entity_id": "user_123",
"status": "failed",
"data": {"code": "EMAIL_TAKEN"},
"created_at": "..."
}
]
}
final result = await tracker.flush((payload) async {
await dio.post('https://api.lu/logs', data: payload);
});
if (!result.success && result.retryable) {
// 5xx / timeout -> coba lagi nanti dengan backoff
}
4. Overlay debug #
// Bubble kecil di pojok (debug only):
TrackerBubble(tracker: tracker)
// Atau full page:
Navigator.push(context,
MaterialPageRoute(builder: (_) => TrackerLogPage(tracker: tracker)));
5. Logout #
await tracker.clear(); // wajib, biar data user tidak bocor
Alur kerja: record → export → bersih #
track() → local (dedup) → export → server → sukses = hapus local
| Operasi | API | Keterangan |
|---|---|---|
| Create | track(keyEvent, id, status, data) |
false = duplikat, di-skip |
| Read | query() / halaman Track Log |
Lihat & filter di device |
| Update | track() lagi dengan data baru |
Log itu immutable; koreksi = event baru (dedup otomatis bedain) |
| Delete | flush() sukses / deleteEvents(ids) / clear() |
Flush sukses langsung hapus local |
Preview vs Flush vs Auto-export #
- Preview (
buildPayload) — cuma INTIP: return JSON tanpa hapus local. Buat debug atau sync manual (copy → POST sendiri →deleteEvents). - Flush (
flush(send)) — KIRIM SEKALI + hapus yang sukses dari local. Device lanjut nge-log data fresh sesudahnya. - Auto-export (
startAutoExport(send, interval: ...)) — flush jalan sendiri tiap interval (misal 5 menit). Gagal = dicoba lagi interval berikutnya. Matikan viastopAutoExport()(otomatis mati saatclear()).
Contoh negative case (API gagal) #
try {
final res = await dio.post('https://api.lu/register', data: form);
await tracker.track(
keyEvent: 'register',
id: userId,
status: TrackStatus.success,
data: {'user_id': res.data['id']},
);
} on DioException catch (e) {
await tracker.track(
keyEvent: 'errorApi',
id: userId,
status: TrackStatus.failed,
data: {'code': e.response?.data['code'], 'url': e.requestOptions.path},
);
}
Kontrak server (tinggal POST payload) #
tracker.startAutoExport(
(payload) => dio.post('https://api.internal.lu/logs', data: payload),
interval: const Duration(minutes: 5),
);
Server terima {batch_id, sent_at, events: [...]}.
Dedup by event_id/batch_id di server biar retry aman.
Sukses simpan → balas 200 → package otomatis hapus local.
Konfigurasi #
LogTracker(
storage: SqfliteTrackStorage(),
config: const LogTrackerConfig(maxQueue: 500, batchSize: 50),
)
maxQueue: maksimal event per device, lebih → FIFO buang paling lamabatchSize: event per sekaliflush()
Example #
Lihat example/ untuk demo lengkap:
custom track, Dio GET, http GET, preview payload, flush, overlay.
cd example
flutter run
Additional information #
- Butuh persist antar restart →
SqfliteTrackStorage() - Butuh unit test cepat →
InMemoryTrackStorage() - Mau engine sendiri (Drift/Hive) → implement
TrackStorage - Issue & kontribusi via GitHub repo di pubspec.