A comprehensive Flutter library for analytics tracking and bug reporting with unified integration across multiple services including Firebase Analytics, Firebase Crashlytics, Microsoft Clarity, Grafana Faro, Splunk, and Google Cloud Logging.
Supported Platforms: iOS • Android
Add to your pubspec.yaml:
dependencies:
engine_tracking: ^1.5.1Initialize the library:
import'package:engine_tracking/engine_tracking.dart';
// Initialize all tracking servicesawaitEngineTrackingInitialize.initWithModels(
analyticsModel:EngineAnalyticsModel(
firebaseAnalyticsConfig:constEngineFirebaseAnalyticsConfig(enabled:true),
clarityConfig:constEngineClarityConfig(enabled:true, projectId:'your-project-id'),
// Configure other services as needed
),
bugTrackingModel:EngineBugTrackingModel(
crashlyticsConfig:constEngineCrashlyticsConfig(enabled:true),
// Configure other services as needed
),
httpTrackingModel:constEngineHttpTrackingModel(
enabled:true,
httpTrackingConfig:EngineHttpTrackingConfig(
enableRequestLogging:true,
enableResponseLogging:true,
logName:'HTTP_TRACKING',
),
),
);
// Start tracking eventsawaitEngineAnalytics.logEvent('app_opened');Analytics Integration
- Firebase Analytics for comprehensive user behavior tracking
- Microsoft Clarity with dual integration (adapter + widget) for session recordings, heatmaps, and custom events
- Grafana Faro for observability and monitoring
- Splunk for enterprise logging and analytics
- Google Cloud Logging for centralized log management
Bug Tracking & Monitoring
- Firebase Crashlytics for crash reporting
- Automatic Flutter error handling
- Custom error tracking with context
- Structured logging with multiple severity levels
Developer Experience
- Type-safe implementation with full null safety
- Automatic session ID correlation across all services
- Flexible service configuration (enable/disable individually)
- Custom widgets with built-in tracking capabilities
- HTTP request monitoring
- Single import entry point
Engine Tracking uses an adapter pattern to provide unified interfaces for multiple analytics and bug tracking services. Each service can be enabled or disabled independently through configuration.
graph LR
A[App Start] --> B[Generate UUID]
B --> C[Session ID]
C --> D[Analytics Events]
C --> E[Bug Reports]
C --> F[Log Entries]
All tracking events automatically include a unique session ID for correlation across services.
graph TD
A[Your App] --> B[EngineAnalytics]
B --> C[Adapters]
C --> D[Firebase Analytics]
C --> E[Microsoft Clarity]
C --> F[Grafana Faro]
C --> G[Splunk]
C --> H[Google Cloud Logging]
graph TD
A[Flutter Errors] --> B[EngineBugTracking]
A2[Custom Errors] --> B
B --> C[Adapters]
C --> D[Firebase Crashlytics]
C --> E[Grafana Faro]
C --> F[Google Cloud Logging]
EngineLog is the central logging system that automatically abstracts and unifies calls to both Analytics and Bug Tracking services. It's the recommended way to log events as it handles service routing automatically.
graph TD
A[Your App] --> B[EngineLog]
B --> C{Log Level}
C -->|debug/info| D[Developer Console]
C -->|warning/error/fatal| E[Developer Console + Services]
E --> F[EngineAnalytics]
E --> G[EngineBugTracking]
F --> H[All Analytics Services]
G --> I[All Bug Tracking Services]
Key Benefits:
- Single API: One method call routes to multiple services
- Automatic Service Detection: Only calls enabled services
- Level-based Routing: Different log levels go to appropriate services
- Context Preservation: Maintains session ID and metadata across all services
- Performance Optimized: No-op when services are disabled
Engine Tracking provides custom widgets that automatically track user interactions and screen lifecycle events.
graph TD
A[EngineStatelessWidget] --> B[buildWithTracking]
C[EngineStatefulWidget] --> D[buildWithTracking]
B --> E[Automatic Screen Tracking]
D --> E
E --> F[screen_initialized]
E --> G[screen_viewed]
E --> H[screen_disposed]
I[User Actions] --> J[logUserAction]
K[State Changes] --> L[logStateChange]
M[Custom Events] --> N[logCustomEvent]
J --> O[EngineLog]
L --> O
N --> O
Automatic navigation tracking with EngineNavigationObserver:
graph LR
A[Navigator] --> B[EngineNavigationObserver]
B --> C[Route Changes]
C --> D[EngineAnalytics.setPage]
D --> E[All Analytics Services]
Engine Tracking provides comprehensive HTTP request/response logging through EngineHttpOverride and EngineHttpTracking using a model-based configuration approach.
graph TD
A[HTTP Requests] --> B[EngineHttpOverride]
B --> C[Request Logging]
B --> D[Response Logging]
B --> E[Error Logging]
C --> F[EngineLog.debug]
D --> F
E --> G[EngineLog.error]
F --> H[All Tracking Services]
G --> H
Key Features:
- Model-based Configuration: Uses
EngineHttpTrackingModelfollowing the same pattern as analytics and bug tracking - Automatic HTTP Logging: Intercepts all HTTP requests/responses
- Configurable Logging: Control what gets logged (headers, body, timing)
- Error Tracking: Automatic error logging for failed requests
- Performance Metrics: Request timing and performance data
- Chain-friendly: Works with existing HttpOverrides (like FaroHttpOverrides)
- Unified Initialization: Integrates with
EngineTrackingInitialize.initWithModels()
Model-based Configuration:
// Development model (verbose logging)constEngineHttpTrackingModel(
enabled:true,
httpTrackingConfig:EngineHttpTrackingConfig(
enableRequestLogging:true,
enableResponseLogging:true,
enableTimingLogging:true,
enableHeaderLogging:true,
enableBodyLogging:true,
maxBodyLogLength:2000,
logName:'HTTP_TRACKING_DEV',
),
)
// Production model (minimal logging)constEngineHttpTrackingModel(
enabled:true,
httpTrackingConfig:EngineHttpTrackingConfig(
enableRequestLogging:true,
enableResponseLogging:true,
enableTimingLogging:true,
enableHeaderLogging:false, // Be careful with sensitive data
enableBodyLogging:false, // Be careful with sensitive data
maxBodyLogLength:500,
logName:'HTTP_TRACKING_PROD',
),
)
// Disabled modelconstEngineHttpTrackingModelDefault() // All tracking disabledAdd to your pubspec.yaml:
dependencies:
engine_tracking: ^1.5.1Run:
flutter pub getThe package includes complete examples demonstrating all functionality:
cd example && flutter runAvailable examples:
- Main Example: Initialization, event tracking, user properties, and navigation
- HTTP Tracking: Requests with PokéAPI and JSONPlaceholder
- View Tracking: Automatic screen tracking system
Use EngineTrackingInitialize to initialize both Analytics and Bug Tracking:
import'package:engine_tracking/engine_tracking.dart';
// All servicesawaitEngineTrackingInitialize.initWithModels(
analyticsModel:EngineAnalyticsModel(/* configs */),
bugTrackingModel:EngineBugTrackingModel(/* configs */),
httpTrackingModel:EngineHttpTrackingModel(/* config */),
);
// Analytics and HTTP tracking onlyawaitEngineTrackingInitialize.initWithModels(
analyticsModel:EngineAnalyticsModel(/* configs */),
bugTrackingModel:null,
httpTrackingModel:EngineHttpTrackingModel(/* config */),
);
// Bug tracking onlyawaitEngineTrackingInitialize.initWithModels(
analyticsModel:null,
bugTrackingModel:EngineBugTrackingModel(/* configs */),
httpTrackingModel:null,
);
// With adapters (granular control)awaitEngineTrackingInitialize.initWithAdapters(
analyticsAdapters: [EngineFirebaseAnalyticsAdapter(/* config */)],
bugTrackingAdapters:null, // Skip bug tracking
);
// Quick initialization (both disabled)awaitEngineTrackingInitialize.initWithDefaults();
// Statusbool bothReady =EngineTrackingInitialize.isInitialized;
bool anyEnabled =EngineTrackingInitialize.isEnabled;
// CleanupawaitEngineTrackingInitialize.dispose();Engine Tracking provides two ways to integrate with Microsoft Clarity:
The EngineClarityAdapter integrates Clarity into the unified analytics system:
final analyticsModel =EngineAnalyticsModel(
clarityConfig:constEngineClarityConfig(
enabled:true,
projectId:'your-clarity-project-id',
),
// ... other configs
);
awaitEngineAnalytics.initWithModel(analyticsModel);
// All analytics calls now include ClarityawaitEngineAnalytics.logEvent('user_action');
awaitEngineAnalytics.setUserId('user_123');
awaitEngineAnalytics.setPage('home_screen');Use EngineWidget to automatically enable session recordings and heatmaps. The widget automatically detects if Clarity has been initialized through the analytics system - no manual configuration required:
voidmain() async {
WidgetsFlutterBinding.ensureInitialized();
// Initialize analytics with Clarity configurationfinal analyticsModel =EngineAnalyticsModel(
clarityConfig:EngineClarityConfig(
enabled:true,
projectId:'your-clarity-project-id',
),
// ... other configurations
);
awaitEngineAnalytics.initWithModel(analyticsModel);
// EngineWidget automatically detects and uses Clarity configuration// No need to pass clarityConfig manually!runApp(EngineWidget(app:MyApp()));
}For complete Clarity integration, initialize analytics and use EngineWidget:
voidmain() async {
WidgetsFlutterBinding.ensureInitialized();
final clarityConfig =EngineClarityConfig(
enabled:true,
projectId:'your-clarity-project-id',
);
// Initialize analytics with Clarity adapterawaitEngineAnalytics.initWithModel(
EngineAnalyticsModel(
clarityConfig: clarityConfig,
// ... other configs
),
);
// EngineWidget automatically detects Clarity configuration// No manual configuration needed!runApp(EngineWidget(app:MyApp()));
}import'package:engine_tracking/engine_tracking.dart';
Future<void> setupTracking() async {
final analyticsModel =EngineAnalyticsModel(
firebaseAnalyticsConfig:constEngineFirebaseAnalyticsConfig(enabled:true),
clarityConfig:constEngineClarityConfig(
enabled:true,
projectId:'your-clarity-project-id',
),
faroConfig:constEngineFaroConfig(
enabled:true,
endpoint:'https://faro-collector.grafana.net/collect',
appName:'YourApp',
appVersion:'1.0.0',
environment:'production',
apiKey:'your-faro-api-key',
),
googleLoggingConfig:constEngineGoogleLoggingConfig(
enabled:true,
projectId:'your-gcp-project',
logName:'engine-tracking',
credentials: {
"type":"service_account",
"project_id":"your-gcp-project",
"private_key_id":"...",
"private_key":"-----BEGIN PRIVATE KEY-----\n...\n-----END PRIVATE KEY-----\n",
"client_email":"your-service-account@your-gcp-project.iam.gserviceaccount.com",
// ... rest of credentials
},
resource: {
'type':'global',
'labels': {'project_id':'your-gcp-project'},
},
),
splunkConfig:constEngineSplunkConfig(enabled:false),
);
final bugTrackingModel =EngineBugTrackingModel(
crashlyticsConfig:constEngineCrashlyticsConfig(enabled:true),
faroConfig:constEngineFaroConfig(
enabled:true,
endpoint:'https://faro-collector.grafana.net/collect',
appName:'YourApp',
appVersion:'1.0.0',
environment:'production',
apiKey:'your-faro-api-key',
),
googleLoggingConfig:constEngineGoogleLoggingConfig(enabled:true, /* configs */),
);
awaitEngineAnalytics.initWithModel(analyticsModel);
awaitEngineBugTracking.initWithModel(bugTrackingModel);
}// Simple event (Session ID included automatically)awaitEngineAnalytics.logEvent('button_clicked');
// Event with parametersawaitEngineAnalytics.logEvent('purchase_completed', {
'item_id':'premium_plan',
'value':29.99,
'currency':'USD',
'category':'subscription',
});
// App open eventawaitEngineAnalytics.logAppOpen();// Set user IDawaitEngineAnalytics.setUserId('user_12345');
// With complete information (for Faro/Clarity)awaitEngineAnalytics.setUserId(
'user_12345',
'user@example.com',
'John Doe',
);
// User propertiesawaitEngineAnalytics.setUserProperty('user_type', 'premium');
awaitEngineAnalytics.setUserProperty('plan', 'monthly');// Simple screenawaitEngineAnalytics.setPage('HomeScreen');
// With complete contextawaitEngineAnalytics.setPage(
'ProductScreen', // Current screen'HomeScreen', // Previous screen'ECommerceApp', // Screen class
);// Structured loggingawaitEngineBugTracking.log('User completed purchase', {
'user_id':'12345',
'product_id':'abc-123',
'amount':29.99,
});
// Capture errorstry {
// code that might fail
} catch (error, stackTrace) {
awaitEngineBugTracking.recordError(
error,
stackTrace,
reason:'Payment processing failure',
);
}
// Set user contextawaitEngineBugTracking.setUserIdentifier('user_12345', 'user@example.com', 'John Doe');
awaitEngineBugTracking.setCustomKey('subscription_plan', 'premium');// Different log levelsawaitEngineLog.debug('Debug information');
awaitEngineLog.info('Informational message');
awaitEngineLog.warning('Warning message');
awaitEngineLog.error('Error occurred');
awaitEngineLog.fatal('Fatal error');
// With additional dataawaitEngineLog.info('User action', data: {
'action':'button_click',
'screen':'home',
'user_id':'12345',
});
// Custom log name and include in analyticsawaitEngineLog.warning('Important warning', logName:'USER_ACTION',
includeInAnalytics:true,
);
// Error logging with exception and stack tracetry {
// risky operation
} catch (error, stackTrace) {
awaitEngineLog.error('Operation failed',
error: error,
stackTrace: stackTrace,
data: {'operation':'user_registration'},
);
}
// Fatal error with complete contextawaitEngineLog.fatal('Critical system failure',
logName:'SYSTEM',
error: exception,
stackTrace: stackTrace,
data: {
'component':'payment_processor',
'user_id':'user_123',
'transaction_id':'tx_456',
},
);classHomePageextendsEngineStatelessWidget {
HomePage({super.key});
@overrideStringget screenName =>'home';
@overrideMap<String, dynamic>?get screenParameters => {
'user_type':'premium',
'version':'1.0.0',
};
@overrideWidgetbuildWithTracking(BuildContext context) {
returnScaffold(
appBar:AppBar(title:constText('Home')),
body:ElevatedButton(
onPressed: () {
logUserAction('cta_clicked', parameters: {
'button_type':'primary',
'location':'header',
});
},
child:constText('Click Me'),
),
);
}
}classShoppingCartPageextendsStatefulWidget {
finalList<Product> initialProducts;
constShoppingCartPage({super.key, requiredthis.initialProducts});
@overrideState<ShoppingCartPage> createState() =>_ShoppingCartPageState();
}
class_ShoppingCartPageStateextendsEngineStatefulWidgetState<ShoppingCartPage> {
lateList<Product> _products;
@overridevoidinitState() {
super.initState();
_products =List.from(widget.initialProducts);
}
@overrideStringget screenName =>'shopping_cart';
@overrideMap<String, dynamic>?get screenParameters => {
'initial_product_count': widget.initialProducts.length,
'cart_value':_calculateTotal(),
};
@overrideWidgetbuildWithTracking(BuildContext context) {
returnScaffold(
appBar:AppBar(title:constText('Shopping Cart')),
body:ListView.builder(
itemCount: _products.length,
itemBuilder: (context, index) {
final product = _products[index];
returnListTile(
title:Text(product.name),
trailing:IconButton(
icon:constIcon(Icons.remove_circle),
onPressed: () {
setState(() {
_products.removeAt(index);
});
logUserAction('product_removed', parameters: {
'product_id': product.id,
'product_name': product.name,
'remaining_count': _products.length,
});
logStateChange('cart_updated', additionalData: {
'action':'removal',
'new_total':_calculateTotal(),
});
},
),
);
},
),
floatingActionButton:FloatingActionButton(
onPressed: () {
logUserAction('checkout_initiated', parameters: {
'product_count': _products.length,
'total_value':_calculateTotal(),
});
},
child:constIcon(Icons.shopping_cart_checkout),
),
);
}
double_calculateTotal() {
return _products.fold(0.0, (sum, product) => sum + product.price);
}
}Engine Tracking provides several specialized widgets for enhanced tracking capabilities:
Automatically wraps your app to enable Microsoft Clarity session recordings when Clarity is initialized. The widget intelligently detects if Clarity has been configured through the analytics system and automatically enables session recordings without requiring manual configuration:
voidmain() async {
WidgetsFlutterBinding.ensureInitialized();
// Initialize analytics with Clarity configurationawaitEngineAnalytics.initWithModel(
EngineAnalyticsModel(
clarityConfig:EngineClarityConfig(
enabled:true,
projectId:'your-clarity-project-id',
),
firebaseAnalyticsConfig:constEngineFirebaseAnalyticsConfig(enabled:true),
// ... other configs
),
);
// EngineWidget automatically detects and enables Clarity session recordings// No manual clarityConfig parameter needed!runApp(EngineWidget(app:MyApp()));
}
classMyAppextendsStatelessWidget {
@overrideWidgetbuild(BuildContext context) {
returnMaterialApp(
home:HomePage(),
navigatorObservers: [EngineNavigationObserver()],
);
}
}
classHomePageextendsStatelessWidget {
@overrideWidgetbuild(BuildContext context) {
returnScaffold(
body:Column(
children: [
ElevatedButton(
onPressed: () async {
// This event goes to all analytics services including ClarityawaitEngineAnalytics.logEvent('button_clicked', {
'button_type':'primary',
'screen':'home',
});
},
child:Text('Track Event'),
),
// Mask sensitive content in Clarity recordingsEngineMaskWidget(
child:Text('Sensitive user data'),
),
],
),
);
}
}Masks sensitive content in session recordings:
classPaymentScreenextendsStatelessWidget {
@overrideWidgetbuild(BuildContext context) {
returnScaffold(
body:Column(
children: [
Text('Order Summary'),
// Mask sensitive payment informationEngineMaskWidget(
child:Column(
children: [
Text('Credit Card: **** **** **** 1234'),
Text('CVV: 123'),
// Unmask non-sensitive info within masked areaEngineUnmaskWidget(
child:Text('Expires: 12/25'),
),
],
),
),
ElevatedButton(
onPressed: () =>processPayment(),
child:Text('Pay Now'),
),
],
),
);
}
}Provides automatic screen tracking and user action logging:
classProductListPageextendsEngineStatelessWidget {
ProductListPage({super.key});
@overrideStringget screenName =>'product_list';
@overrideMap<String, dynamic>?get screenParameters => {
'category':'electronics',
'sort_by':'price',
};
@overrideWidgetbuildWithTracking(BuildContext context) {
returnScaffold(
appBar:AppBar(title:Text('Products')),
body:ListView.builder(
itemBuilder: (context, index) {
returnListTile(
title:Text('Product $index'),
onTap: () {
// Automatically tracked user actionlogUserAction('product_selected', parameters: {
'product_id': index,
'product_name':'Product $index',
});
// Navigate to product detailsNavigator.push(context, MaterialPageRoute(builder: (_) =>ProductDetailPage()));
},
);
},
),
floatingActionButton:FloatingActionButton(
onPressed: () {
// Log custom eventslogCustomEvent('filter_opened');
},
child:Icon(Icons.filter_list),
),
);
}
}Includes state change tracking in addition to all EngineStatelessWidget features:
classShoppingCartPageextendsStatefulWidget {
@overrideState<ShoppingCartPage> createState() =>_ShoppingCartPageState();
}
class_ShoppingCartPageStateextendsEngineStatefulWidgetState<ShoppingCartPage> {
List<CartItem> _items = [];
@overrideStringget screenName =>'shopping_cart';
@overrideMap<String, dynamic>?get screenParameters => {
'initial_item_count': _items.length,
'cart_value':_calculateTotal(),
};
@overrideWidgetbuildWithTracking(BuildContext context) {
returnScaffold(
appBar:AppBar(title:Text('Shopping Cart')),
body:ListView.builder(
itemCount: _items.length,
itemBuilder: (context, index) {
returnListTile(
title:Text(_items[index].name),
trailing:IconButton(
icon:Icon(Icons.remove),
onPressed: () =>_removeItem(index),
),
);
},
),
);
}
void_removeItem(int index) {
final removedItem = _items[index];
setState(() {
_items.removeAt(index);
});
// Track user actionlogUserAction('item_removed', parameters: {
'item_id': removedItem.id,
'remaining_items': _items.length,
});
// Track state changelogStateChange('cart_updated', additionalData: {
'action':'item_removal',
'new_total':_calculateTotal(),
});
}
double_calculateTotal() {
return _items.fold(0.0, (sum, item) => sum + item.price);
}
}Automatic navigation tracking with EngineNavigationObserver:
classMyAppextendsStatelessWidget {
@overrideWidgetbuild(BuildContext context) {
returnMaterialApp(
title:'My App',
// Add the navigation observer for automatic screen tracking
navigatorObservers: [
EngineNavigationObserver(),
],
home:HomePage(),
routes: {
'/products': (context) =>ProductListPage(),
'/cart': (context) =>ShoppingCartPage(),
'/profile': (context) =>ProfilePage(),
},
);
}
}The EngineNavigationObserver automatically:
- Tracks route changes and screen transitions
- Calls
EngineAnalytics.setPage()with screen names - Provides navigation context for analytics
- Works seamlessly with both named routes and direct navigation
Engine Tracking provides comprehensive HTTP request/response logging using a model-based approach:
import'package:engine_tracking/engine_tracking.dart';
import'package:http/http.dart'as http;
voidmain() async {
// Initialize Engine Tracking with HTTP tracking modelawaitEngineTrackingInitialize.initWithModels(
analyticsModel: myAnalyticsModel,
bugTrackingModel: myBugTrackingModel,
// Add HTTP tracking model
httpTrackingModel:constEngineHttpTrackingModel(
enabled:true,
httpTrackingConfig:EngineHttpTrackingConfig(
enableRequestLogging:true,
enableResponseLogging:true,
enableTimingLogging:true,
enableHeaderLogging:true,
enableBodyLogging:true,
maxBodyLogLength:2000,
logName:'HTTP_TRACKING_DEV',
),
),
);
runApp(MyApp());
}
// HTTP requests are now automatically loggedclassApiService {
Future<User> getUser(String userId) async {
// This request will be automatically logged with:// - Request details (method, URL, headers, timing)// - Response details (status, headers, timing)// - Error details (if request fails)final response =await http.get(
Uri.parse('https://api.example.com/users/$userId'),
headers: {'Authorization':'Bearer $token'},
);
if (response.statusCode ==200) {
returnUser.fromJson(json.decode(response.body));
} else {
throwApiException('Failed to load user');
}
}
Future<void> updateUser(User user) async {
// POST requests are also automatically trackedfinal response =await http.post(
Uri.parse('https://api.example.com/users/${user.id}'),
headers: {
'Content-Type':'application/json',
'Authorization':'Bearer $token',
},
body: json.encode(user.toJson()),
);
if (response.statusCode !=200) {
throwApiException('Failed to update user');
}
}
}Model Configuration Examples:
// Development model: Full logging with headers and bodyconst devModel =EngineHttpTrackingModel(
enabled:true,
httpTrackingConfig:EngineHttpTrackingConfig(
enableRequestLogging:true,
enableResponseLogging:true,
enableTimingLogging:true,
enableHeaderLogging:true,
enableBodyLogging:true,
maxBodyLogLength:2000,
logName:'API_DEV',
),
);
// Production model: Minimal logging, no sensitive dataconst prodModel =EngineHttpTrackingModel(
enabled:true,
httpTrackingConfig:EngineHttpTrackingConfig(
enableRequestLogging:true,
enableResponseLogging:true,
enableTimingLogging:true,
enableHeaderLogging:false, // Disable for security
enableBodyLogging:false, // Disable for security
maxBodyLogLength:500,
logName:'API_PROD',
),
);
// Disabled modelconst disabledModel =EngineHttpTrackingModelDefault();Advanced Usage:
// Initialize directly with modelEngineHttpTracking.initWithModel(devModel);
// Update model at runtimeEngineHttpTracking.updateModel(prodModel);
// Update model at runtimeEngineHttpTracking.updateModel(prodModel);
// Log custom HTTP-related eventsawaitEngineHttpTracking.logCustomEvent(
'API rate limit reached',
data: {
'endpoint':'/api/users',
'retry_after':60,
'request_count':100,
},
);
// Get HTTP tracking statisticsfinal stats =EngineHttpTracking.getStats();
print('HTTP Tracking enabled: ${stats['is_enabled']}');Backward Compatibility:
// Legacy configuration method (deprecated but still supported)@Deprecated('Use EngineHttpTrackingModel instead')
EngineHttpTracking.initialize(config);// Check if analytics is enabledif (EngineAnalytics.isEnabled) {
print('✅ Analytics is active');
}
// Check specific servicesif (EngineAnalytics.isFirebaseInitialized) {
print('🔥 Firebase Analytics active');
}
if (EngineAnalytics.isClarityInitialized) {
print('👁️ Microsoft Clarity active');
}
if (EngineAnalytics.isFaroInitialized) {
print('📊 Grafana Faro active');
}
if (EngineAnalytics.isSplunkInitialized) {
print('🔍 Splunk active');
}
if (EngineAnalytics.isGoogleLoggingInitialized) {
print('☁️ Google Cloud Logging active');
}Contributions are welcome! Please:
- Fork the project
- Create a feature branch (
git checkout -b feature/AmazingFeature) - Commit your changes (
git commit -m 'Add some AmazingFeature') - Push to the branch (
git push origin feature/AmazingFeature) - Open a Pull Request
- Follow existing code patterns
- Document new features
- Test on both Android and iOS
- Update the CHANGELOG.md
This project is licensed under the MIT License - see the LICENSE file for details.
Developed by STMR - Mobile solutions specialists.
STMR is a company focused on developing innovative technology solutions for mobile devices, specializing in robust architectures, optimized performance, and exceptional user experiences.
To provide high-quality Flutter tools and libraries that accelerate enterprise mobile application development while maintaining the highest standards of security, performance, and usability.
Tip: For maximum efficiency, configure only the services you actually use. The library is optimized to work with any combination of enabled or disabled services. With automatic Session ID, you now have complete log correlation and advanced centralization!