Skip to content

Commit 5f42d4f

Browse files
authored
refactor: redesign logging system for CLI-friendly output (#561)
* refactor: redesign logging system for CLI-friendly output * refactor: remove ANSI color support from logger * fix: address PR review feedback
1 parent a0b4412 commit 5f42d4f

13 files changed

Lines changed: 275 additions & 187 deletions

File tree

CLAUDE.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ go mod verify
4646

4747
- **Platform code**: use build tags (`_darwin.go`, `_windows.go`, `_linux.go`)
4848
- **Error handling**: `fmt.Errorf("context: %w", err)` for wrapping, never `_ =` to ignore errors
49-
- **Logging**: `log.Debugf` for record-level issues, `log.Warnf` for user-visible warnings. Extract methods should return errors, not log them.
49+
- **Logging**: `log.Debugf` for record-level diagnostics, `log.Infof` for user-facing progress/status, `log.Warnf` for unexpected conditions. Extract methods should return errors, not log them.
5050
- **Naming**: follow Go conventions — `Config` not `BrowserConfig`, `Extract` not `BrowsingData`
5151
- **Tests**: use `t.TempDir()` for filesystem tests, `go-sqlmock` for database tests
5252
- **Architecture**: see `rfcs/` for design documents

browser/chromium/chromium.go

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -187,7 +187,6 @@ func (b *Browser) extractCategory(data *types.BrowserData, cat types.Category, m
187187
func discoverProfiles(userDataDir string, sources map[types.Category][]sourcePath) []string {
188188
entries, err := os.ReadDir(userDataDir)
189189
if err != nil {
190-
log.Debugf("read user data dir %s: %v", userDataDir, err)
191190
return nil
192191
}
193192

browser/chromium/extract_cookie.go

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ const defaultCookieQuery = `SELECT name, encrypted_value, host_key, path,
1616
has_expires, is_persistent FROM cookies`
1717

1818
func extractCookies(masterKey []byte, path string) ([]types.CookieEntry, error) {
19+
var decryptFails int
20+
var lastErr error
1921
cookies, err := sqliteutil.QueryRows(path, false, defaultCookieQuery,
2022
func(rows *sql.Rows) (types.CookieEntry, error) {
2123
var (
@@ -33,7 +35,8 @@ func extractCookies(masterKey []byte, path string) ([]types.CookieEntry, error)
3335

3436
value, err := decryptValue(masterKey, encryptedValue)
3537
if err != nil {
36-
log.Debugf("decrypt cookie %s on %s: %v", name, host, err)
38+
decryptFails++
39+
lastErr = err
3740
}
3841
value = stripCookieHash(value, host)
3942
return types.CookieEntry{
@@ -52,6 +55,9 @@ func extractCookies(masterKey []byte, path string) ([]types.CookieEntry, error)
5255
if err != nil {
5356
return nil, err
5457
}
58+
if decryptFails > 0 {
59+
log.Debugf("decrypt cookies: %d failed: %v", decryptFails, lastErr)
60+
}
5561

5662
sort.Slice(cookies, func(i, j int) bool {
5763
return cookies[i].CreatedAt.After(cookies[j].CreatedAt)

browser/chromium/extract_creditcard.go

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,9 @@ const defaultCreditCardQuery = `SELECT COALESCE(guid, ''), name_on_card, expirat
1212
card_number_encrypted, COALESCE(nickname, ''), COALESCE(billing_address_id, '') FROM credit_cards`
1313

1414
func extractCreditCards(masterKey []byte, path string) ([]types.CreditCardEntry, error) {
15-
return sqliteutil.QueryRows(path, false, defaultCreditCardQuery,
15+
var decryptFails int
16+
var lastErr error
17+
cards, err := sqliteutil.QueryRows(path, false, defaultCreditCardQuery,
1618
func(rows *sql.Rows) (types.CreditCardEntry, error) {
1719
var guid, name, month, year, nickname, address string
1820
var encNumber []byte
@@ -21,7 +23,8 @@ func extractCreditCards(masterKey []byte, path string) ([]types.CreditCardEntry,
2123
}
2224
number, err := decryptValue(masterKey, encNumber)
2325
if err != nil {
24-
log.Debugf("decrypt credit card for %s: %v", name, err)
26+
decryptFails++
27+
lastErr = err
2528
}
2629
return types.CreditCardEntry{
2730
GUID: guid,
@@ -33,4 +36,11 @@ func extractCreditCards(masterKey []byte, path string) ([]types.CreditCardEntry,
3336
Address: address,
3437
}, nil
3538
})
39+
if err != nil {
40+
return nil, err
41+
}
42+
if decryptFails > 0 {
43+
log.Debugf("decrypt credit cards: %d failed: %v", decryptFails, lastErr)
44+
}
45+
return cards, nil
3646
}

browser/chromium/extract_password.go

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ func extractPasswords(masterKey []byte, path string) ([]types.LoginEntry, error)
1616
}
1717

1818
func extractPasswordsWithQuery(masterKey []byte, path, query string) ([]types.LoginEntry, error) {
19+
var decryptFails int
20+
var lastErr error
1921
logins, err := sqliteutil.QueryRows(path, false, query,
2022
func(rows *sql.Rows) (types.LoginEntry, error) {
2123
var url, username string
@@ -26,7 +28,8 @@ func extractPasswordsWithQuery(masterKey []byte, path, query string) ([]types.Lo
2628
}
2729
password, err := decryptValue(masterKey, pwd)
2830
if err != nil {
29-
log.Debugf("decrypt password for %s: %v", url, err)
31+
decryptFails++
32+
lastErr = err
3033
}
3134
return types.LoginEntry{
3235
URL: url,
@@ -38,6 +41,9 @@ func extractPasswordsWithQuery(masterKey []byte, path, query string) ([]types.Lo
3841
if err != nil {
3942
return nil, err
4043
}
44+
if decryptFails > 0 {
45+
log.Debugf("decrypt passwords: %d failed: %v", decryptFails, lastErr)
46+
}
4147

4248
sort.Slice(logins, func(i, j int) bool {
4349
return logins[i].CreatedAt.After(logins[j].CreatedAt)

browser/firefox/extract_password.go

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,8 @@ func extractPasswords(masterKey []byte, path string) ([]types.LoginEntry, error)
3737
}
3838

3939
var logins []types.LoginEntry
40+
var decryptFails int
41+
var lastErr error
4042
for _, v := range gjson.GetBytes(data, "logins").Array() {
4143
url := v.Get("formSubmitURL").String()
4244
if url == "" {
@@ -45,11 +47,13 @@ func extractPasswords(masterKey []byte, path string) ([]types.LoginEntry, error)
4547

4648
user, err := decryptPBE(v.Get("encryptedUsername").String(), masterKey)
4749
if err != nil {
48-
log.Debugf("decrypt firefox username for %s: %v", url, err)
50+
decryptFails++
51+
lastErr = err
4952
}
5053
pwd, err := decryptPBE(v.Get("encryptedPassword").String(), masterKey)
5154
if err != nil {
52-
log.Debugf("decrypt firefox password for %s: %v", url, err)
55+
decryptFails++
56+
lastErr = err
5357
}
5458

5559
logins = append(logins, types.LoginEntry{
@@ -59,6 +63,9 @@ func extractPasswords(masterKey []byte, path string) ([]types.LoginEntry, error)
5963
CreatedAt: timestamp(v.Get("timeCreated").Int() / 1000),
6064
})
6165
}
66+
if decryptFails > 0 {
67+
log.Debugf("decrypt firefox login fields: %d failed: %v", decryptFails, lastErr)
68+
}
6269

6370
sort.Slice(logins, func(i, j int) bool {
6471
return logins[i].CreatedAt.After(logins[j].CreatedAt)

browser/firefox/firefox.go

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -188,7 +188,6 @@ type resolvedPath struct {
188188
func discoverProfiles(userDataDir string, sources map[types.Category][]sourcePath) []string {
189189
entries, err := os.ReadDir(userDataDir)
190190
if err != nil {
191-
log.Debugf("read user data dir %s: %v", userDataDir, err)
192191
return nil
193192
}
194193

cmd/hack-browser-data/dump.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ func dumpCmd() *cobra.Command {
5858
}
5959

6060
for _, b := range browsers {
61+
log.Infof("Extracting %s/%s...", b.BrowserName(), b.ProfileName())
6162
data, extractErr := b.Extract(categories)
6263
if extractErr != nil {
6364
log.Errorf("extract %s/%s: %v", b.BrowserName(), b.ProfileName(), extractErr)
@@ -73,7 +74,7 @@ func dumpCmd() *cobra.Command {
7374
if err := fileutil.CompressDir(outputDir); err != nil {
7475
return fmt.Errorf("compress: %w", err)
7576
}
76-
log.Warnf("compressed: %s/%s.zip", outputDir, filepath.Base(outputDir))
77+
log.Infof("Compressed: %s/%s.zip", outputDir, filepath.Base(outputDir))
7778
}
7879
return nil
7980
},
Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,16 @@
1-
package level
1+
package log
22

3-
// Level defines all the available levels we can log at
3+
// Level defines all the available levels we can log at.
44
type Level int32
55

66
const (
77
// DebugLevel is the lowest level of logging.
88
// Debug logs are intended for debugging and development purposes.
99
DebugLevel Level = iota + 1
1010

11+
// InfoLevel is used for user-facing progress and status messages.
12+
InfoLevel
13+
1114
// WarnLevel is used for undesired but relatively expected events,
1215
// which may indicate a problem.
1316
WarnLevel
@@ -24,14 +27,16 @@ const (
2427
func (l Level) String() string {
2528
switch l {
2629
case DebugLevel:
27-
return "DEBUG"
30+
return "DBG"
31+
case InfoLevel:
32+
return "INF"
2833
case WarnLevel:
29-
return "WARN"
34+
return "WRN"
3035
case ErrorLevel:
31-
return "ERROR"
36+
return "ERR"
3237
case FatalLevel:
33-
return "FATAL"
38+
return "FTL"
3439
default:
35-
return "UNKNOWN"
40+
return "???"
3641
}
3742
}

log/log.go

Lines changed: 20 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,44 +1,52 @@
11
package log
22

3-
import (
4-
"github.com/moond4rk/hackbrowserdata/log/level"
5-
)
3+
import "fmt"
64

75
// defaultLogger is the default logger used by the package-level functions.
86
var defaultLogger = NewLogger(nil)
97

108
func SetVerbose() {
11-
defaultLogger.SetLevel(level.DebugLevel)
9+
defaultLogger.SetLevel(DebugLevel)
1210
}
1311

1412
func Debug(args ...any) {
15-
defaultLogger.Debug(args...)
13+
defaultLogger.logMsg(DebugLevel, fmt.Sprint(args...))
1614
}
1715

1816
func Debugf(format string, args ...any) {
19-
defaultLogger.Debugf(format, args...)
17+
defaultLogger.logMsg(DebugLevel, fmt.Sprintf(format, args...))
18+
}
19+
20+
func Info(args ...any) {
21+
defaultLogger.logMsg(InfoLevel, fmt.Sprint(args...))
22+
}
23+
24+
func Infof(format string, args ...any) {
25+
defaultLogger.logMsg(InfoLevel, fmt.Sprintf(format, args...))
2026
}
2127

2228
func Warn(args ...any) {
23-
defaultLogger.Warn(args...)
29+
defaultLogger.logMsg(WarnLevel, fmt.Sprint(args...))
2430
}
2531

2632
func Warnf(format string, args ...any) {
27-
defaultLogger.Warnf(format, args...)
33+
defaultLogger.logMsg(WarnLevel, fmt.Sprintf(format, args...))
2834
}
2935

3036
func Error(args ...any) {
31-
defaultLogger.Error(args...)
37+
defaultLogger.logMsg(ErrorLevel, fmt.Sprint(args...))
3238
}
3339

3440
func Errorf(format string, args ...any) {
35-
defaultLogger.Errorf(format, args...)
41+
defaultLogger.logMsg(ErrorLevel, fmt.Sprintf(format, args...))
3642
}
3743

3844
func Fatal(args ...any) {
39-
defaultLogger.Fatal(args...)
45+
defaultLogger.logMsg(FatalLevel, fmt.Sprint(args...))
46+
osExit(1)
4047
}
4148

4249
func Fatalf(format string, args ...any) {
43-
defaultLogger.Fatalf(format, args...)
50+
defaultLogger.logMsg(FatalLevel, fmt.Sprintf(format, args...))
51+
osExit(1)
4452
}

0 commit comments

Comments
 (0)