Use log levels when logging to console

This commit is contained in:
Roland Geider
2025-01-25 12:45:33 +01:00
parent ae7ae5dbdc
commit 58e7a52e3d
13 changed files with 106 additions and 45 deletions

View File

@@ -2,6 +2,7 @@ import 'dart:io';
import 'package:drift/drift.dart';
import 'package:drift/native.dart';
import 'package:logging/logging.dart';
import 'package:path/path.dart' as p;
import 'package:path_provider/path_provider.dart';
import 'package:wger/database/exercises/type_converters.dart';
@@ -68,6 +69,8 @@ class Equipments extends Table {
@DriftDatabase(tables: [Exercises, Muscles, Equipments, Categories, Languages])
class ExerciseDatabase extends _$ExerciseDatabase {
final _logger = Logger('ExerciseDatabase');
ExerciseDatabase() : super(_openConnection());
// Named constructor for creating in-memory database
@@ -100,6 +103,7 @@ class ExerciseDatabase extends _$ExerciseDatabase {
Future<void> deleteEverything() {
return transaction(() async {
for (final table in allTables) {
_logger.info('Deleting db cache table ${table.actualTableName}');
await delete(table).go();
}
});

View File

@@ -2,6 +2,7 @@ import 'dart:io';
import 'package:drift/drift.dart';
import 'package:drift/native.dart';
import 'package:logging/logging.dart';
import 'package:path/path.dart' as p;
import 'package:path_provider/path_provider.dart';
@@ -21,6 +22,8 @@ class Ingredients extends Table {
@DriftDatabase(tables: [Ingredients])
class IngredientDatabase extends _$IngredientDatabase {
final _logger = Logger('IngredientDatabase');
IngredientDatabase() : super(_openConnection());
// Named constructor for creating in-memory database
@@ -53,6 +56,7 @@ class IngredientDatabase extends _$IngredientDatabase {
Future<void> deleteEverything() {
return transaction(() async {
for (final table in allTables) {
_logger.info('Deleting db cache table ${table.actualTableName}');
await delete(table).go();
}
});

View File

@@ -16,8 +16,10 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:logging/logging.dart';
import 'package:provider/provider.dart';
import 'package:wger/core/locator.dart';
import 'package:wger/providers/add_exercise.dart';
@@ -55,7 +57,15 @@ import 'package:wger/widgets/core/settings.dart';
import 'providers/auth.dart';
void _setupLogging() {
Logger.root.level = kDebugMode ? Level.ALL : Level.INFO;
Logger.root.onRecord.listen((record) {
print('${record.level.name}: ${record.time} [${record.loggerName}] ${record.message}');
});
}
void main() async {
_setupLogging();
//zx.setLogEnabled(kDebugMode);
// Needs to be called before runApp
@@ -63,12 +73,14 @@ void main() async {
// Locator to initialize exerciseDB
await ServiceLocator().configure();
// Application
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp(); // This widget is the root of your application.
const MyApp();
@override
Widget build(BuildContext context) {
return MultiProvider(
@@ -143,7 +155,7 @@ class MyApp extends StatelessWidget {
highContrastDarkTheme: wgerDarkThemeHc,
themeMode: user.themeMode,
home: auth.isAuth
? const HomeTabsScreen()
? HomeTabsScreen()
: FutureBuilder(
future: auth.tryAutoLogin(),
builder: (ctx, authResultSnapshot) =>
@@ -156,7 +168,7 @@ class MyApp extends StatelessWidget {
FormScreen.routeName: (ctx) => const FormScreen(),
GalleryScreen.routeName: (ctx) => const GalleryScreen(),
GymModeScreen.routeName: (ctx) => const GymModeScreen(),
HomeTabsScreen.routeName: (ctx) => const HomeTabsScreen(),
HomeTabsScreen.routeName: (ctx) => HomeTabsScreen(),
MeasurementCategoriesScreen.routeName: (ctx) => const MeasurementCategoriesScreen(),
MeasurementEntriesScreen.routeName: (ctx) => const MeasurementEntriesScreen(),
NutritionalPlansScreen.routeName: (ctx) => const NutritionalPlansScreen(),

View File

@@ -18,13 +18,13 @@
import 'dart:async';
import 'dart:convert';
import 'dart:developer';
import 'dart:io';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';
import 'package:http/http.dart' as http;
import 'package:logging/logging.dart';
import 'package:package_info_plus/package_info_plus.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:version/version.dart';
@@ -39,6 +39,8 @@ enum LoginActions {
}
class AuthProvider with ChangeNotifier {
final _logger = Logger('AuthProvider');
String? token;
String? serverUrl;
String? serverVersion;
@@ -193,7 +195,7 @@ class AuthProvider with ChangeNotifier {
Future<bool> tryAutoLogin() async {
final prefs = await SharedPreferences.getInstance();
if (!prefs.containsKey(PREFS_USER)) {
log('autologin failed');
_logger.info('autologin failed');
return false;
}
final extractedUserData = json.decode(prefs.getString(PREFS_USER)!);
@@ -201,7 +203,7 @@ class AuthProvider with ChangeNotifier {
token = extractedUserData['token'];
serverUrl = extractedUserData['serverUrl'];
log('autologin successful');
_logger.info('autologin successful');
setApplicationVersion();
setServerVersion();
notifyListeners();
@@ -210,7 +212,7 @@ class AuthProvider with ChangeNotifier {
}
Future<void> logout({bool shouldNotify = true}) async {
log('logging out');
_logger.fine('logging out');
token = null;
serverUrl = null;
dataInit = false;

View File

@@ -17,11 +17,14 @@
*/
import 'package:flutter/material.dart';
import 'package:logging/logging.dart';
import 'package:wger/exceptions/http_exception.dart';
import 'package:wger/models/body_weight/weight_entry.dart';
import 'package:wger/providers/base_provider.dart';
class BodyWeightProvider with ChangeNotifier {
final _logger = Logger('BodyWeightProvider');
final WgerBaseProvider baseProvider;
static const BODY_WEIGHT_URL = 'weightentry';
@@ -61,6 +64,8 @@ class BodyWeightProvider with ChangeNotifier {
}
Future<List<WeightEntry>> fetchAndSetEntries() async {
_logger.info('Fetching all body weight entries');
// Process the response
final data = await baseProvider.fetchPaginated(baseProvider.makeUrl(
BODY_WEIGHT_URL,

View File

@@ -18,10 +18,10 @@
import 'dart:async';
import 'dart:convert';
import 'dart:developer';
import 'package:drift/drift.dart';
import 'package:flutter/material.dart';
import 'package:logging/logging.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:wger/core/locator.dart';
import 'package:wger/database/exercises/exercise_database.dart';
@@ -36,6 +36,8 @@ import 'package:wger/models/exercises/muscle.dart';
import 'package:wger/providers/base_provider.dart';
class ExercisesProvider with ChangeNotifier {
final _logger = Logger('ExercisesProvider');
final WgerBaseProvider baseProvider;
late ExerciseDatabase database;
@@ -44,7 +46,6 @@ class ExercisesProvider with ChangeNotifier {
}
static const EXERCISE_CACHE_DAYS = 7;
static const EXERCISE_FETCH_HOURS = 4;
static const CACHE_VERSION = 4;
static const exerciseInfoUrlPath = 'exercisebaseinfo';
@@ -237,6 +238,7 @@ class ExercisesProvider with ChangeNotifier {
}
Future<void> fetchAndSetCategoriesFromApi() async {
_logger.info('Loading exercise categories from API');
final categories = await baseProvider.fetchPaginated(baseProvider.makeUrl(categoriesUrlPath));
for (final category in categories) {
_categories.add(ExerciseCategory.fromJson(category));
@@ -244,6 +246,7 @@ class ExercisesProvider with ChangeNotifier {
}
Future<void> fetchAndSetMusclesFromApi() async {
_logger.info('Loading muscles from API');
final muscles = await baseProvider.fetchPaginated(baseProvider.makeUrl(musclesUrlPath));
for (final muscle in muscles) {
@@ -252,6 +255,7 @@ class ExercisesProvider with ChangeNotifier {
}
Future<void> fetchAndSetEquipmentsFromApi() async {
_logger.info('Loading equipment from API');
final equipments = await baseProvider.fetchPaginated(baseProvider.makeUrl(equipmentUrlPath));
for (final equipment in equipments) {
@@ -260,6 +264,8 @@ class ExercisesProvider with ChangeNotifier {
}
Future<void> fetchAndSetLanguagesFromApi() async {
_logger.info('Loading languages from API');
final languageData = await baseProvider.fetchPaginated(baseProvider.makeUrl(languageUrlPath));
for (final language in languageData) {
@@ -271,9 +277,12 @@ class ExercisesProvider with ChangeNotifier {
///
/// If the exercise is not known locally, it is fetched from the server.
Future<Exercise> fetchAndSetExercise(int exerciseId) async {
// _logger.finer('Fetching exercise $exerciseId');
try {
final exercise = findExerciseById(exerciseId);
// _logger.finer('Found $exerciseId in provider list');
// Note: no await since we don't care for the updated data right now. It
// will be written to the db whenever the request finishes and we will get
// the updated exercise the next time
@@ -312,11 +321,16 @@ class ExercisesProvider with ChangeNotifier {
// Exercise is already known locally
if (exerciseDb != null) {
final nextFetch = exerciseDb.lastFetched.add(const Duration(hours: EXERCISE_FETCH_HOURS));
// _logger.fine('Exercise $exerciseId found in local cache');
final nextFetch = exerciseDb.lastFetched.add(const Duration(days: EXERCISE_CACHE_DAYS));
exercise = Exercise.fromApiDataString(exerciseDb.data, _languages);
// Fetch and update
if (nextFetch.isBefore(DateTime.now())) {
_logger.fine(
'Re-fetching exercise $exerciseId from API since last fetch was ${exerciseDb.lastFetched}',
);
final apiData = await baseProvider.fetch(
baseProvider.makeUrl(exerciseInfoUrlPath, id: exerciseId),
);
@@ -342,6 +356,7 @@ class ExercisesProvider with ChangeNotifier {
}
// New exercise, fetch and insert to DB
} else {
_logger.fine('New exercise $exerciseId, fetching from API');
final baseData = await baseProvider.fetch(
baseProvider.makeUrl(exerciseInfoUrlPath, id: exerciseId),
);
@@ -356,6 +371,7 @@ class ExercisesProvider with ChangeNotifier {
lastFetched: DateTime.now(),
),
);
_logger.finer('Saved exercise ${exercise.id!} to db cache');
}
}
@@ -402,7 +418,8 @@ class ExercisesProvider with ChangeNotifier {
/// - Equipment
/// - Exercises (only local cache)
Future<void> fetchAndSetInitialData() async {
clear();
// clear();
_logger.info('Fetching initial exercise data');
await initCacheTimesLocalPrefs();
@@ -429,7 +446,7 @@ class ExercisesProvider with ChangeNotifier {
}
final exercisesDb = await database.select(database.exercises).get();
log('Loaded ${exercisesDb.length} exercises from cache');
_logger.info('Loaded ${exercisesDb.length} exercises from DB cache');
exercises = exercisesDb.map((e) => Exercise.fromApiDataString(e.data, _languages)).toList();
}
@@ -465,7 +482,7 @@ class ExercisesProvider with ChangeNotifier {
final lastUpdateApi = DateTime.parse(exerciseData['last_update_global']);
if (exercise != null && lastUpdateApi.isAfter(exercise.lastUpdate)) {
// TODO: timezones 🥳
print(
_logger.fine(
'Exercise ${exercise.id}: update API $lastUpdateApi | Update DB: ${exercise.lastUpdate}',
);
(database.update(database.exercises)..where((e) => e.id.equals(exerciseData['id']))).write(
@@ -493,7 +510,7 @@ class ExercisesProvider with ChangeNotifier {
if (muscles.isNotEmpty) {
_muscles = muscles.map((e) => e.data).toList();
log('Loaded ${_muscles.length} muscles from cache');
_logger.info('Loaded ${_muscles.length} muscles from cache');
return;
}
}
@@ -511,7 +528,7 @@ class ExercisesProvider with ChangeNotifier {
PREFS_LAST_UPDATED_MUSCLES,
validTill.toIso8601String(),
);
log('Wrote ${_muscles.length} muscles from cache. Valid till $validTill');
_logger.fine('Saved ${_muscles.length} muscles to cache (valid till $validTill)');
}
/// Fetches and sets the available categories
@@ -527,7 +544,7 @@ class ExercisesProvider with ChangeNotifier {
if (categories.isNotEmpty) {
_categories = categories.map((e) => e.data).toList();
log('Loaded ${categories.length} categories from cache');
_logger.info('Loaded ${categories.length} categories from cache');
return;
}
}
@@ -545,6 +562,7 @@ class ExercisesProvider with ChangeNotifier {
PREFS_LAST_UPDATED_CATEGORIES,
validTill.toIso8601String(),
);
_logger.fine('Saved ${_categories.length} categories to cache (valid till $validTill)');
}
/// Fetches and sets the available languages
@@ -560,6 +578,7 @@ class ExercisesProvider with ChangeNotifier {
if (languages.isNotEmpty) {
_languages = languages.map((e) => e.data).toList();
_logger.info('Loaded ${languages.length} languages from cache');
return;
}
}
@@ -572,11 +591,13 @@ class ExercisesProvider with ChangeNotifier {
LanguagesCompanion.insert(id: e.id, data: e),
);
});
validTill = DateTime.now().add(const Duration(days: EXERCISE_CACHE_DAYS));
await prefs.setString(
PREFS_LAST_UPDATED_LANGUAGES,
validTill.toIso8601String(),
);
_logger.info('Saved ${languages.length} languages to cache (valid till $validTill)');
}
/// Fetches and sets the available equipment
@@ -592,7 +613,7 @@ class ExercisesProvider with ChangeNotifier {
if (equipments.isNotEmpty) {
_equipment = equipments.map((e) => e.data).toList();
log('Loaded ${equipment.length} equipment from cache');
_logger.info('Loaded ${equipment.length} equipment from cache');
return;
}
}
@@ -610,6 +631,7 @@ class ExercisesProvider with ChangeNotifier {
PREFS_LAST_UPDATED_EQUIPMENT,
validTill.toIso8601String(),
);
_logger.fine('Saved ${_equipment.length} equipment entries to cache (valid till $validTill)');
}
/// Searches for an exercise

View File

@@ -17,6 +17,7 @@
*/
import 'package:flutter/material.dart';
import 'package:logging/logging.dart';
import 'package:wger/exceptions/http_exception.dart';
import 'package:wger/exceptions/no_such_entry_exception.dart';
import 'package:wger/models/measurements/measurement_category.dart';
@@ -24,6 +25,8 @@ import 'package:wger/models/measurements/measurement_entry.dart';
import 'package:wger/providers/base_provider.dart';
class MeasurementProvider with ChangeNotifier {
final _logger = Logger('MeasurementProvider');
static const _categoryUrl = 'measurement-category';
static const _entryUrl = 'measurement';
@@ -82,6 +85,8 @@ class MeasurementProvider with ChangeNotifier {
/// Fetches and sets the measurement categories and their entries
Future<void> fetchAndSetAllCategoriesAndEntries() async {
_logger.info('Fetching all measurement categories and entries');
await fetchAndSetCategories();
await Future.wait(_categories.map((e) => fetchAndSetCategoryEntries(e.id!)).toList());
}

View File

@@ -17,9 +17,9 @@
*/
import 'dart:convert';
import 'dart:developer';
import 'package:flutter/material.dart';
import 'package:logging/logging.dart';
import 'package:wger/core/locator.dart';
import 'package:wger/database/ingredients/ingredients_database.dart';
import 'package:wger/exceptions/http_exception.dart';
@@ -35,6 +35,8 @@ import 'package:wger/models/nutrition/nutritional_plan.dart';
import 'package:wger/providers/base_provider.dart';
class NutritionPlansProvider with ChangeNotifier {
final _logger = Logger('NutritionPlansProvider');
static const _nutritionalPlansPath = 'nutritionplan';
static const _nutritionalPlansInfoPath = 'nutritionplaninfo';
static const _mealPath = 'meal';
@@ -128,6 +130,8 @@ class NutritionPlansProvider with ChangeNotifier {
/// Fetches a plan fully, i.e. with all corresponding child objects
Future<NutritionalPlan> fetchAndSetPlanFull(int planId) async {
_logger.fine('Fetching full nutritional plan $planId');
NutritionalPlan plan;
try {
plan = findById(planId);
@@ -310,7 +314,7 @@ class NutritionPlansProvider with ChangeNotifier {
if (ingredientDb != null) {
ingredient = Ingredient.fromJson(jsonDecode(ingredientDb.data));
ingredients.add(ingredient);
log("Loaded ingredient '${ingredient.name}' from db cache");
_logger.info("Loaded ingredient '${ingredient.name}' from db cache");
// Prune old entries
if (DateTime.now()
@@ -331,7 +335,7 @@ class NutritionPlansProvider with ChangeNotifier {
lastFetched: DateTime.now(),
),
);
log("Saved ingredient '${ingredient.name}' to db cache");
_logger.finer("Saved ingredient '${ingredient.name}' to db cache");
}
}
@@ -341,7 +345,7 @@ class NutritionPlansProvider with ChangeNotifier {
/// Loads the available ingredients from the local cache
Future<void> fetchIngredientsFromCache() async {
final ingredientDb = await database.select(database.ingredients).get();
log('Read ${ingredientDb.length} ingredients from db cache');
_logger.info('Read ${ingredientDb.length} ingredients from db cache');
if (ingredientDb.isNotEmpty) {
ingredients = ingredientDb.map((e) => Ingredient.fromJson(jsonDecode(e.data))).toList();
}

View File

@@ -48,16 +48,12 @@ class UserProvider with ChangeNotifier {
Future<void> _loadThemeMode() async {
final prefsDarkMode = await prefs.getBool(PREFS_USER_DARK_THEME);
print(prefsDarkMode);
if (prefsDarkMode == null) {
themeMode = ThemeMode.system;
} else {
themeMode = prefsDarkMode ? ThemeMode.dark : ThemeMode.light;
}
print(themeMode);
notifyListeners();
}
@@ -87,7 +83,7 @@ class UserProvider with ChangeNotifier {
/// Save the user's profile to the server
Future<void> saveProfile() async {
final data = await baseProvider.post(
await baseProvider.post(
profile!.toJson(),
baseProvider.makeUrl(PROFILE_URL),
);
@@ -95,7 +91,7 @@ class UserProvider with ChangeNotifier {
/// Verify the user's email
Future<void> verifyEmail() async {
final verificationData = await baseProvider.fetch(baseProvider.makeUrl(
await baseProvider.fetch(baseProvider.makeUrl(
PROFILE_URL,
objectMethod: VERIFY_EMAIL,
));

View File

@@ -17,9 +17,9 @@
*/
import 'dart:convert';
import 'dart:developer' as dev;
import 'package:flutter/material.dart';
import 'package:logging/logging.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:wger/exceptions/http_exception.dart';
import 'package:wger/helpers/consts.dart';
@@ -37,6 +37,8 @@ import 'package:wger/providers/base_provider.dart';
import 'package:wger/providers/exercises.dart';
class WorkoutPlansProvider with ChangeNotifier {
final _logger = Logger('WorkoutPlansProvider');
static const _workoutPlansUrlPath = 'workout';
static const _daysUrlPath = 'day';
static const _setsUrlPath = 'set';
@@ -178,6 +180,8 @@ class WorkoutPlansProvider with ChangeNotifier {
/// Fetches a workout plan fully, i.e. with all corresponding child attributes
Future<WorkoutPlan> fetchAndSetWorkoutPlanFull(int workoutId) async {
_logger.fine('Fetching full workout plan $workoutId');
// Load a list of all settings so that we can search through it
//
// This is a bit ugly, but saves us sending lots of requests later on
@@ -252,8 +256,8 @@ class WorkoutPlansProvider with ChangeNotifier {
log.exerciseBase = await _exercises.fetchAndSetExercise(log.exerciseBaseId);
plan.logs.add(log);
} catch (e) {
dev.log('fire! fire!');
dev.log(e.toString());
_logger.warning('fire! fire!');
_logger.warning(e.toString());
}
}
@@ -340,7 +344,7 @@ class WorkoutPlansProvider with ChangeNotifier {
unitData['weightUnit'].forEach(
(e) => _weightUnits.add(WeightUnit.fromJson(e)),
);
dev.log(
_logger.info(
"Read workout units data from cache. Valid till ${unitData['expiresIn']}",
);
return;

View File

@@ -16,11 +16,10 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import 'dart:developer';
import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'package:logging/logging.dart';
import 'package:provider/provider.dart';
import 'package:rive/rive.dart';
import 'package:wger/providers/auth.dart';
@@ -38,7 +37,10 @@ import 'package:wger/screens/weight_screen.dart';
import 'package:wger/screens/workout_plans_screen.dart';
class HomeTabsScreen extends StatefulWidget {
const HomeTabsScreen();
final _logger = Logger('HomeTabsScreen');
HomeTabsScreen();
static const routeName = '/dashboard2';
@override
@@ -84,7 +86,7 @@ class _HomeTabsScreenState extends State<HomeTabsScreen> with SingleTickerProvid
final userProvider = context.read<UserProvider>();
// Base data
log('Loading base data');
widget._logger.info('Loading base data');
try {
await Future.wait([
authProvider.setServerVersion(),
@@ -94,12 +96,12 @@ class _HomeTabsScreenState extends State<HomeTabsScreen> with SingleTickerProvid
exercisesProvider.fetchAndSetInitialData(),
]);
} catch (e) {
log('Exception loading base data');
log(e.toString());
widget._logger.warning('Exception loading base data');
widget._logger.warning(e.toString());
}
// Plans, weight and gallery
log('Loading plans, weight, measurements and gallery');
widget._logger.info('Loading plans, weight, measurements and gallery');
try {
await Future.wait([
galleryProvider.fetchAndSetGallery(),
@@ -109,24 +111,24 @@ class _HomeTabsScreenState extends State<HomeTabsScreen> with SingleTickerProvid
measurementProvider.fetchAndSetAllCategoriesAndEntries(),
]);
} catch (e) {
log('Exception loading plans, weight, measurements and gallery');
log(e.toString());
widget._logger.warning('Exception loading plans, weight, measurements and gallery');
widget._logger.info(e.toString());
}
// Current nutritional plan
log('Loading current nutritional plan');
widget._logger.info('Loading current nutritional plan');
try {
if (nutritionPlansProvider.currentPlan != null) {
final plan = nutritionPlansProvider.currentPlan!;
await nutritionPlansProvider.fetchAndSetPlanFull(plan.id!);
}
} catch (e) {
log('Exception loading current nutritional plan');
log(e.toString());
widget._logger.warning('Exception loading current nutritional plan');
widget._logger.warning(e.toString());
}
// Current workout plan
log('Loading current workout plan');
widget._logger.info('Loading current workout plan');
if (workoutPlansProvider.activePlan != null) {
final planId = workoutPlansProvider.activePlan!.id!;
await workoutPlansProvider.fetchAndSetWorkoutPlanFull(planId);

View File

@@ -810,7 +810,7 @@ packages:
source: hosted
version: "1.0.2"
logging:
dependency: transitive
dependency: "direct main"
description:
name: logging
sha256: c8245ada5f1717ed44271ed1c26b8ce85ca3228fd2ffdb75468ab01979309d61

View File

@@ -68,6 +68,7 @@ dependencies:
url_launcher: ^6.3.1
version: ^3.0.2
video_player: ^2.9.2
logging: ^1.3.0
dependency_overrides:
intl: ^0.19.0