Skip to content

Commit 8f64b0c

Browse files
committed
Migrate Stat Tracker #2
1 parent 616ce7e commit 8f64b0c

File tree

8 files changed

+79
-115
lines changed

8 files changed

+79
-115
lines changed

lib/src/constants.dart

Lines changed: 0 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -48,19 +48,6 @@ const String publishPath = 'publish';
4848
const String previewPath = 'publish_preview';
4949
const String templatesPath = 'templates';
5050

51-
/// Stats tracking constants
52-
const String statsCollection = 'stats';
53-
const String lostStatsDoc = '_lost';
54-
const String viewsField = 'views';
55-
const String writesField = 'writes';
56-
const String readsField = 'reads';
57-
const String bundleDownloadsField = 'bundle_downloads';
58-
const String fontDownloadsField = 'font_downloads';
59-
const String actionsField = 'actions';
60-
const String cloudActionsField = 'cloud_actions';
61-
const String populatedLayoutDownloadsField = 'populated_layout_downloads';
62-
const String layoutViewsField = 'layout_views';
63-
6451
/// The template url for the svg icons.
6552
/// {{style}}: The style of the icon. e.g. materialiconsoutlined
6653
/// {{name}}: The name of the icon. e.g. home

lib/src/data/cloud_database.dart

Lines changed: 18 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -225,14 +225,14 @@ class FirestoreCloudDatabase extends CloudDatabase {
225225

226226
// Create project doc if missing.
227227
final snapshot = await rootRef.get();
228-
StatTracker.instance.trackRead('cloudDatabase/init');
228+
StatTracker.instance.track(StatType.read, 'cloudDatabase/init');
229229

230230
// Do nothing if project doc exists.
231231
if (snapshot.exists) return;
232232

233233
// Create project doc if it does not exist.
234234
await rootRef.set({'project': identifier});
235-
StatTracker.instance.trackWrite('cloudDatabase/init');
235+
StatTracker.instance.track(StatType.write, 'cloudDatabase/init');
236236

237237
DebugLogger.instance
238238
.printInfo('Done initializing for $identifier', name: name);
@@ -314,7 +314,7 @@ class FirestoreCloudDatabase extends CloudDatabase {
314314
// Auto generate id if desired.
315315
if (autoGenerateId) {
316316
final document = await rootRef.collection(path).add(value);
317-
StatTracker.instance.trackWrite('cloudDatabase/addDocument');
317+
StatTracker.instance.track(StatType.write, 'cloudDatabase/addDocument');
318318

319319
DebugLogger.instance.printInfo(
320320
'Document added: ${document.path}',
@@ -337,7 +337,7 @@ class FirestoreCloudDatabase extends CloudDatabase {
337337

338338
// Get snapshot to check if document exists.
339339
final snapshot = await docRef.get();
340-
StatTracker.instance.trackRead('cloudDatabase/addDocument');
340+
StatTracker.instance.track(StatType.read, 'cloudDatabase/addDocument');
341341

342342
if (skipCreationIfDocumentExists && snapshot.exists) {
343343
DebugLogger.instance.printInfo(
@@ -349,7 +349,7 @@ class FirestoreCloudDatabase extends CloudDatabase {
349349

350350
// Set document.
351351
await docRef.set(value);
352-
StatTracker.instance.trackWrite('cloudDatabase/addDocument');
352+
StatTracker.instance.track(StatType.write, 'cloudDatabase/addDocument');
353353

354354
DebugLogger.instance.printInfo(
355355
'Document added: ${docRef.path}/$documentId',
@@ -381,7 +381,7 @@ class FirestoreCloudDatabase extends CloudDatabase {
381381

382382
// TODO: Should we do update instead of set?
383383
await docRef.set(value, SetOptions(merge: true));
384-
StatTracker.instance.trackWrite('cloudDatabase/updateDocument');
384+
StatTracker.instance.track(StatType.write, 'cloudDatabase/updateDocument');
385385

386386
DebugLogger.instance.printInfo(
387387
'Document updated: ${docRef.path}',
@@ -395,13 +395,13 @@ class FirestoreCloudDatabase extends CloudDatabase {
395395
final docRef = getDocPath(path, documentId);
396396

397397
final snapshot = await docRef.get();
398-
StatTracker.instance.trackRead('cloudDatabase/removeDocument');
398+
StatTracker.instance.track(StatType.read, 'cloudDatabase/removeDocument');
399399

400400
// TODO: Do we have to check for existence?
401401
if (!snapshot.exists) return false;
402402

403403
await docRef.delete();
404-
StatTracker.instance.trackWrite('cloudDatabase/removeDocument');
404+
StatTracker.instance.track(StatType.write, 'cloudDatabase/removeDocument');
405405

406406
return true;
407407
}
@@ -412,7 +412,7 @@ class FirestoreCloudDatabase extends CloudDatabase {
412412
final docRef = getDocPath(path, documentId);
413413

414414
final snapshot = await docRef.get();
415-
StatTracker.instance.trackRead('cloudDatabase/getDocumentData');
415+
StatTracker.instance.track(StatType.read, 'cloudDatabase/getDocumentData');
416416

417417
final data = snapshot.data() ?? {};
418418
return sanitizeCloudDataForUse(data, docId: snapshot.id);
@@ -422,7 +422,7 @@ class FirestoreCloudDatabase extends CloudDatabase {
422422
Stream<Map<String, dynamic>> streamDocument(String path, String documentId) {
423423
final docRef = getDocPath(path, documentId);
424424
return docRef.snapshots().map((snapshot) {
425-
StatTracker.instance.trackRead('cloudDatabase/streamDocument');
425+
StatTracker.instance.track(StatType.read, 'cloudDatabase/streamDocument');
426426

427427
return snapshot.data()?.let(
428428
(value) => sanitizeCloudDataForUse(value, docId: snapshot.id)) ??
@@ -450,8 +450,10 @@ class FirestoreCloudDatabase extends CloudDatabase {
450450
// Listen to the stream and update the variable.
451451
final subscription = stream.listen(
452452
(data) {
453-
StatTracker.instance
454-
.trackRead('cloudDatabase/streamDocumentToVariable');
453+
StatTracker.instance.track(
454+
StatType.read,
455+
'cloudDatabase/streamDocumentToVariable',
456+
);
455457

456458
DebugLogger.instance.printInfo(
457459
'Document stream update from cloud storage: $path/$documentId',
@@ -534,8 +536,10 @@ class FirestoreCloudDatabase extends CloudDatabase {
534536
// Listen to the stream and update the variable.
535537
final subscription = stream.listen(
536538
(snapshot) {
537-
StatTracker.instance
538-
.trackRead('cloudDatabase/streamCollectionToVariable');
539+
StatTracker.instance.track(
540+
StatType.read,
541+
'cloudDatabase/streamCollectionToVariable',
542+
);
539543

540544
final docs = snapshot.docs
541545
.map((doc) => sanitizeCloudDataForUse(doc.data(), docId: doc.id))

lib/src/data/data_manager.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1516,7 +1516,7 @@ class DataManager {
15161516
.printInfo('\tLayout [$layoutID] has no fonts.', name: name);
15171517
}
15181518

1519-
StatTracker.instance.trackPopulatedLayoutDownload(layoutID);
1519+
StatTracker.instance.track(StatType.populatedLayoutDownload, layoutID);
15201520
return true;
15211521
}
15221522

lib/src/data/firebase_data_repository.dart

Lines changed: 24 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,10 @@ class FirebaseDataRepository extends NetworkDataRepository {
2727
firestore.collection(source.serverPath).doc(projectID);
2828

2929
return publishModelDoc.snapshots().map((event) {
30-
StatTracker.instance.trackRead('${source.serverPath}/streamPublishModel');
30+
StatTracker.instance.track(
31+
StatType.read,
32+
'${source.serverPath}/streamPublishModel',
33+
);
3134

3235
final Map<String, dynamic>? data = event.data();
3336
if (data == null || data.isEmpty) {
@@ -69,8 +72,10 @@ class FirebaseDataRepository extends NetworkDataRepository {
6972
);
7073
return null;
7174
}
72-
StatTracker.instance
73-
.trackRead('${source.serverPath}/downloadLayoutModel');
75+
StatTracker.instance.track(
76+
StatType.read,
77+
'${source.serverPath}/downloadLayoutModel',
78+
);
7479

7580
final Map<String, dynamic> data = value.data() ?? {};
7681

@@ -105,7 +110,10 @@ class FirebaseDataRepository extends NetworkDataRepository {
105110
.doc(fontID);
106111

107112
return fontDoc.get().then((value) {
108-
StatTracker.instance.trackRead('${source.serverPath}/downloadFontModel');
113+
StatTracker.instance.track(
114+
StatType.read,
115+
'${source.serverPath}/downloadFontModel',
116+
);
109117

110118
final Map<String, dynamic> data = value.data() ?? {};
111119

@@ -139,7 +147,10 @@ class FirebaseDataRepository extends NetworkDataRepository {
139147
.doc(apiId);
140148

141149
return apiDoc.get().then((value) {
142-
StatTracker.instance.trackRead('${source.serverPath}/downloadApi');
150+
StatTracker.instance.track(
151+
StatType.read,
152+
'${source.serverPath}/downloadApi',
153+
);
143154

144155
final Map<String, dynamic> data = value.data() ?? {};
145156

@@ -173,8 +184,10 @@ class FirebaseDataRepository extends NetworkDataRepository {
173184
.doc(layoutID);
174185

175186
return variablesDoc.get().then((value) {
176-
StatTracker.instance
177-
.trackRead('${source.serverPath}/downloadLayoutVariables');
187+
StatTracker.instance.track(
188+
StatType.read,
189+
'${source.serverPath}/downloadLayoutVariables',
190+
);
178191

179192
final Map<String, dynamic> data = value.data() ?? {};
180193

@@ -209,8 +222,10 @@ class FirebaseDataRepository extends NetworkDataRepository {
209222
.doc(layoutID);
210223

211224
return conditionsDoc.get().then((value) {
212-
StatTracker.instance
213-
.trackRead('${source.serverPath}/downloadLayoutConditions');
225+
StatTracker.instance.track(
226+
StatType.read,
227+
'${source.serverPath}/downloadLayoutConditions',
228+
);
214229

215230
final Map<String, dynamic> data = value.data() ?? {};
216231

lib/src/data/network_data_repository.dart

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ abstract class NetworkDataRepository {
5959
return null;
6060
}
6161

62-
StatTracker.instance.trackBundleDownload();
62+
StatTracker.instance.track(StatType.bundleDownload);
6363

6464
final Map<String, dynamic> modelDoc =
6565
jsonDecode(utf8.decode(result.bodyBytes));
@@ -174,7 +174,7 @@ abstract class NetworkDataRepository {
174174
try {
175175
final http.Response response = await http.get(Uri.parse(url));
176176
if (response.statusCode != 200) return null;
177-
StatTracker.instance.trackFontDownload();
177+
StatTracker.instance.track(StatType.fontDownload);
178178

179179
return Uint8List.view(response.bodyBytes.buffer);
180180
} catch (e) {

lib/src/functions/functions_repository.dart

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -70,9 +70,9 @@ class FunctionsRepository {
7070
final Codelessly codelessly = context.read<Codelessly>();
7171
switch (action.type) {
7272
case ActionType.loadFromCloudStorage || ActionType.setCloudStorage:
73-
StatTracker.instance.trackCloudAction(action);
73+
StatTracker.instance.track(StatType.cloudAction, action.type.name);
7474
default:
75-
StatTracker.instance.trackAction(action);
75+
StatTracker.instance.track(StatType.action, action.type.name);
7676
}
7777

7878
switch (action.type) {

lib/src/logging/stat_tracker.dart

Lines changed: 31 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,9 @@
11
import 'dart:async';
22
import 'dart:convert';
33

4-
import 'package:codelessly_api/codelessly_api.dart';
54
import 'package:http/http.dart' as http;
65
import 'package:meta/meta.dart';
76

8-
import '../../codelessly_sdk.dart';
97
import '../utils/debouncer.dart';
108

119
/// A class that tracks statistics of various operations in the SDK.
@@ -75,80 +73,40 @@ class StatTracker {
7573
forceRunAfter: 20,
7674
);
7775

78-
void incrementField(String field) {
79-
statBatch[field] = (statBatch[field] ?? 0) + 1;
80-
}
81-
82-
/// Tracks one complete visual view of a Codelessly CloudUI Layout.
83-
Future<void> trackView() {
84-
if (disabled) return Future.value();
85-
86-
incrementField(viewsField);
87-
return sendBatch();
88-
}
89-
90-
/// Tracks one document read operation.
91-
Future<void> trackRead(String label) {
92-
if (disabled) return Future.value();
93-
94-
incrementField('$readsField/$label');
95-
return sendBatch();
96-
}
97-
98-
/// Tracks one document write operation.
99-
Future<void> trackWrite(String label) {
100-
if (disabled) return Future.value();
101-
102-
incrementField('$writesField/$label');
103-
return sendBatch();
104-
}
105-
106-
/// Tracks one complete populated layout download operation.
107-
Future<void> trackPopulatedLayoutDownload(String label) {
108-
if (disabled) return Future.value();
109-
110-
incrementField('$populatedLayoutDownloadsField/$label');
111-
return sendBatch();
112-
}
113-
114-
/// Tracks a layout as being viewed, determined by the life cycle of the
115-
/// CodelesslyWidget.
116-
Future<void> trackLayoutView(String label) {
117-
if (disabled) return Future.value();
118-
119-
incrementField('$layoutViewsField/$label');
120-
return sendBatch();
121-
}
122-
123-
/// Tracks one bundle download operation from the CDN.
124-
Future<void> trackBundleDownload() {
125-
if (disabled) return Future.value();
126-
127-
incrementField(bundleDownloadsField);
128-
return sendBatch();
129-
}
130-
131-
/// Tracks one font download operation from the CDN.
132-
Future<void> trackFontDownload() {
76+
/// Tracks a stat with optional sublabel and count
77+
///
78+
/// Example usages:
79+
/// ```dart
80+
/// // Track view
81+
/// track(StatType.view);
82+
///
83+
/// // Track read with label
84+
/// track(StatType.read, 'cloudDatabase/init');
85+
///
86+
/// // Track multiple downloads
87+
/// track(StatType.bundleDownload, null, 5);
88+
/// ```
89+
Future<void> track(StatType type, [String? sublabel, int count = 1]) {
13390
if (disabled) return Future.value();
13491

135-
incrementField(fontDownloadsField);
92+
final field = sublabel != null ? '${type.path}/$sublabel' : type.path;
93+
statBatch[field] = (statBatch[field] ?? 0) + count;
13694
return sendBatch();
13795
}
96+
}
13897

139-
/// Tracks one action operation.
140-
Future<void> trackAction(ActionModel action) {
141-
if (disabled) return Future.value();
142-
143-
incrementField('$actionsField/${action.type.name}');
144-
return sendBatch();
145-
}
146-
147-
/// Tracks one cloud action operation.
148-
Future<void> trackCloudAction(ActionModel action) {
149-
if (disabled) return Future.value();
150-
151-
incrementField('$cloudActionsField/${action.type.name}');
152-
return sendBatch();
153-
}
98+
/// Types of statistics that can be tracked
99+
enum StatType {
100+
view('views'),
101+
read('reads'),
102+
write('writes'),
103+
bundleDownload('bundle_downloads'),
104+
fontDownload('font_downloads'),
105+
action('actions'),
106+
cloudAction('cloud_actions'),
107+
populatedLayoutDownload('populated_layout_downloads'),
108+
layoutView('layout_views');
109+
110+
final String path;
111+
const StatType(this.path);
154112
}

lib/src/ui/codelessly_widget.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -561,7 +561,7 @@ class _CodelesslyWidgetState extends State<CodelesslyWidget> {
561561

562562
if (!didView) {
563563
didView = true;
564-
StatTracker.instance.trackView();
564+
StatTracker.instance.track(StatType.view);
565565
}
566566

567567
final layoutWidget = Material(

0 commit comments

Comments
 (0)