Skip to content

Commit 398ae2b

Browse files
authored
Merge pull request #409 from DevKor-github/codexd/issue-389-production-safe-logging
[codex] Redact production logging
2 parents 16f388b + 170bfe4 commit 398ae2b

20 files changed

Lines changed: 440 additions & 226 deletions

File tree

android/app/src/main/kotlin/club/devkor/ontime/AlarmRingingActivity.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ class AlarmRingingActivity : Activity() {
6464

6565
override fun onCreate(savedInstanceState: Bundle?) {
6666
super.onCreate(savedInstanceState)
67-
NativeLog.d(TAG, "AlarmRingingActivity onCreate action=${intent?.action} extras=${intent?.extras}")
67+
NativeLog.d(TAG, "AlarmRingingActivity onCreate ${NativeLog.summarizeIntent(intent)}")
6868
configureWindow()
6969
capturePayload(intent)
7070
buildContent()
@@ -74,7 +74,7 @@ class AlarmRingingActivity : Activity() {
7474

7575
override fun onNewIntent(intent: Intent) {
7676
super.onNewIntent(intent)
77-
NativeLog.d(TAG, "AlarmRingingActivity onNewIntent action=${intent.action} extras=${intent.extras}")
77+
NativeLog.d(TAG, "AlarmRingingActivity onNewIntent ${NativeLog.summarizeIntent(intent)}")
7878
setIntent(intent)
7979
if (intent.action == NativeAlarmReceiver.ACTION_DISMISS_ALARM) {
8080
dismissAlarm()

android/app/src/main/kotlin/club/devkor/ontime/MainActivity.kt

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -29,10 +29,10 @@ open class MainActivity : FlutterActivity() {
2929

3030
override fun onCreate(savedInstanceState: Bundle?) {
3131
super.onCreate(savedInstanceState)
32-
NativeLog.d(TAG, "MainActivity onCreate action=${intent?.action} extras=${intent?.extras}")
32+
NativeLog.d(TAG, "MainActivity onCreate ${NativeLog.summarizeIntent(intent)}")
3333
configureAlarmLaunchWindow(intent)
3434
payloadFromIntent(intent)?.let {
35-
NativeLog.d(TAG, "Captured launch payload from onCreate: $it")
35+
NativeLog.d(TAG, "Captured launch payload from onCreate ${NativeLog.summarizeMap(it)}")
3636
launchPayload = it
3737
}
3838
}
@@ -64,7 +64,7 @@ open class MainActivity : FlutterActivity() {
6464
"scheduleNativeAlarm" -> scheduleNativeAlarm(call, result)
6565
"cancelNativeAlarm" -> cancelNativeAlarm(call, result)
6666
"getLaunchPayload" -> {
67-
NativeLog.d(TAG, "getLaunchPayload -> $launchPayload")
67+
NativeLog.d(TAG, "getLaunchPayload -> ${NativeLog.summarizeMap(launchPayload)}")
6868
result.success(launchPayload)
6969
launchPayload = null
7070
}
@@ -75,11 +75,11 @@ open class MainActivity : FlutterActivity() {
7575

7676
override fun onNewIntent(intent: Intent) {
7777
super.onNewIntent(intent)
78-
NativeLog.d(TAG, "MainActivity onNewIntent action=${intent.action} extras=${intent.extras}")
78+
NativeLog.d(TAG, "MainActivity onNewIntent ${NativeLog.summarizeIntent(intent)}")
7979
setIntent(intent)
8080
configureAlarmLaunchWindow(intent)
8181
payloadFromIntent(intent)?.let {
82-
NativeLog.d(TAG, "Captured launch payload from onNewIntent: $it")
82+
NativeLog.d(TAG, "Captured launch payload from onNewIntent ${NativeLog.summarizeMap(it)}")
8383
launchPayload = it
8484
methodChannel?.invokeMethod("alarmLaunch", it)
8585
}
@@ -96,7 +96,7 @@ open class MainActivity : FlutterActivity() {
9696
val triggerAtMillis = (args["alarmTime"] as? Number)?.toLong()
9797
val scheduleId = args["scheduleId"]?.toString()
9898
if (triggerAtMillis == null || scheduleId.isNullOrEmpty()) {
99-
NativeLog.w(TAG, "scheduleNativeAlarm invalid args=$args")
99+
NativeLog.w(TAG, "scheduleNativeAlarm invalid ${NativeLog.summarizeMap(args)}")
100100
result.error("invalidArguments", "Missing scheduleId or alarmTime", null)
101101
return
102102
}
@@ -128,7 +128,11 @@ open class MainActivity : FlutterActivity() {
128128
PendingIntent.FLAG_UPDATE_CURRENT,
129129
)
130130
if (alarmIntent == null) {
131-
NativeLog.w(TAG, "scheduleNativeAlarm unable to build broadcast pending intent args=$args")
131+
NativeLog.w(
132+
TAG,
133+
"scheduleNativeAlarm unable to build broadcast pending intent " +
134+
NativeLog.summarizeMap(args),
135+
)
132136
result.error("invalidArguments", "Unable to build alarm intent", null)
133137
return
134138
}

android/app/src/main/kotlin/club/devkor/ontime/NativeAlarmReceiver.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -203,7 +203,7 @@ class NativeAlarmReceiver : BroadcastReceiver() {
203203
}
204204

205205
override fun onReceive(context: Context, intent: Intent) {
206-
NativeLog.d(TAG, "NativeAlarmReceiver onReceive action=${intent.action} extras=${intent.extras}")
206+
NativeLog.d(TAG, "NativeAlarmReceiver onReceive ${NativeLog.summarizeIntent(intent)}")
207207
when (intent.action) {
208208
ACTION_FIRE_ALARM -> handleFireAlarm(context, intent)
209209
ACTION_DISMISS_ALARM -> handleDismissAlarm(context, intent)

android/app/src/main/kotlin/club/devkor/ontime/NativeLog.kt

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package club.devkor.ontime
22

3+
import android.content.Intent
34
import android.util.Log
45

56
object NativeLog {
@@ -26,4 +27,27 @@ object NativeLog {
2627
Log.e(tag, message, throwable)
2728
}
2829
}
30+
31+
fun summarizeIntent(intent: Intent?): String {
32+
if (intent == null) return "action=null extrasKeys=0"
33+
val extras = intent.extras
34+
val values = if (extras == null) {
35+
null
36+
} else {
37+
extras.keySet().associateWith { key -> extras.get(key) }
38+
}
39+
return "action=${intent.action} ${summarizeMap(values)}"
40+
}
41+
42+
fun summarizeMap(values: Map<*, *>?): String {
43+
if (values == null) return "keys=0"
44+
val scheduleId = values["scheduleId"]?.toString()
45+
val nativeAlarmId = values["nativeAlarmId"]?.toString()
46+
val type = values["type"]?.toString()
47+
val parts = mutableListOf("keys=${values.size}")
48+
if (!scheduleId.isNullOrBlank()) parts.add("scheduleId=$scheduleId")
49+
if (!nativeAlarmId.isNullOrBlank()) parts.add("nativeAlarmId=$nativeAlarmId")
50+
if (!type.isNullOrBlank()) parts.add("type=$type")
51+
return parts.joinToString(" ")
52+
}
2953
}

lib/core/dio/interceptors/token_interceptor.dart

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import 'package:dio/dio.dart';
2-
import 'package:flutter/material.dart';
3-
import 'package:on_time_front/data/data_sources/token_local_data_source.dart';
42
import 'package:on_time_front/core/di/di_setup.dart';
3+
import 'package:on_time_front/core/logging/app_logger.dart';
4+
import 'package:on_time_front/data/data_sources/token_local_data_source.dart';
55
import 'package:on_time_front/domain/entities/token_entity.dart';
66
import 'package:on_time_front/domain/repositories/user_repository.dart';
77

@@ -31,8 +31,10 @@ class TokenInterceptor implements InterceptorsWrapper {
3131
final token = await tokenLocalDataSource.getToken();
3232

3333
options.headers['Authorization'] = 'Bearer ${token.accessToken}';
34-
} catch (e) {
35-
debugPrint(e.toString());
34+
} catch (error) {
35+
AppLogger.debug(
36+
'token load failed for request errorType=${error.runtimeType}',
37+
);
3638
}
3739
handler.next(options);
3840
}
@@ -113,7 +115,7 @@ class TokenInterceptor implements InterceptorsWrapper {
113115
),
114116
);
115117
if (res.statusCode == 200) {
116-
debugPrint("token refreshing success");
118+
AppLogger.debug('token refreshing success');
117119
final accessToken = res.headers.value('authorization');
118120
final refreshedRefreshToken =
119121
res.headers.value('authorization-refresh');
@@ -129,11 +131,14 @@ class TokenInterceptor implements InterceptorsWrapper {
129131
);
130132
return true;
131133
} else {
132-
debugPrint("refresh token fail ${res.statusMessage ?? res.toString()}");
134+
AppLogger.debug(
135+
'refresh token failed status=${res.statusCode} '
136+
'message=${res.statusMessage}',
137+
);
133138
return false;
134139
}
135140
} catch (error) {
136-
debugPrint("refresh token fail $error");
141+
AppLogger.debug('refresh token failed errorType=${error.runtimeType}');
137142
return false;
138143
}
139144
}

lib/core/logging/app_logger.dart

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,30 @@ final class AppLogger {
7575
return '$redacted length=${token.length}';
7676
}
7777

78+
static String summarizeMap(
79+
Map<dynamic, dynamic>? values, {
80+
Iterable<String> allowedKeys = const [
81+
'scheduleId',
82+
'nativeAlarmId',
83+
'type',
84+
'promptVariant',
85+
],
86+
}) {
87+
if (values == null) return 'null';
88+
final allowedKeySet = allowedKeys.toSet();
89+
final visibleEntries = <String>[];
90+
for (final key in allowedKeySet) {
91+
if (!values.containsKey(key)) continue;
92+
final value = values[key];
93+
if (value == null) continue;
94+
visibleEntries.add('$key=${redactValueForKey(key, value)}');
95+
}
96+
return [
97+
'keys=${values.length}',
98+
...visibleEntries,
99+
].join(' ');
100+
}
101+
78102
static String redactText(String message) {
79103
var result = message.replaceAllMapped(
80104
RegExp(

0 commit comments

Comments
 (0)