wip
1package log
2
3import (
4 "fmt"
5 "io"
6 "log"
7 "os"
8 "strings"
9 "time"
10)
11
12var (
13 verboseLog *log.Logger
14 infoLog *log.Logger
15 errorLog *log.Logger
16)
17
18func Init(verbose bool) {
19 infoWriter := os.Stdout
20 verboseWriter := io.Discard
21 if verbose {
22 verboseWriter = os.Stdout
23 }
24
25 // Use no flags, we'll add our own ISO 8601 timestamps
26 infoLog = log.New(infoWriter, "", 0)
27 verboseLog = log.New(verboseWriter, "", 0)
28 errorLog = log.New(os.Stderr, "", 0)
29}
30
31// timestamp returns current time with milliseconds (local time, no timezone)
32func timestamp() string {
33 return time.Now().Format("2006-01-02T15:04:05.000")
34}
35
36func Verbose(format string, v ...interface{}) {
37 verboseLog.Printf("%s [VERBOSE] %s", timestamp(), fmt.Sprintf(format, v...))
38}
39
40func Info(format string, v ...interface{}) {
41 infoLog.Printf("%s [INFO] %s", timestamp(), fmt.Sprintf(format, v...))
42}
43
44func Warn(format string, v ...interface{}) {
45 infoLog.Printf("%s [WARN] %s", timestamp(), fmt.Sprintf(format, v...))
46}
47
48func Error(format string, v ...interface{}) {
49 errorLog.Printf("%s [ERROR] %s", timestamp(), fmt.Sprintf(format, v...))
50}
51
52func Fatal(format string, v ...interface{}) {
53 errorLog.Fatalf("%s [FATAL] %s", timestamp(), fmt.Sprintf(format, v...))
54}
55
56// Banner prints a startup banner
57func Banner(version string) {
58 banner := `
59╔════════════════════════════════════════════════════════════╗
60║ ║
61║ █████╗ ████████╗███████╗ ██████╗ █████╗ ███╗ ██╗ ║
62║ ██╔══██╗╚══██╔══╝██╔════╝██╔════╝██╔══██╗████╗ ██║ ║
63║ ███████║ ██║ ███████╗██║ ███████║██╔██╗ ██║ ║
64║ ██╔══██║ ██║ ╚════██║██║ ██╔══██║██║╚██╗██║ ║
65║ ██║ ██║ ██║ ███████║╚██████╗██║ ██║██║ ╚████║ ║
66║ ╚═╝ ╚═╝ ╚═╝ ╚══════╝ ╚═════╝╚═╝ ╚═╝╚═╝ ╚═══╝ ║
67║ ║
68║ AT Protocol Network Scanner & Indexer ║
69║ Version %s ║
70║ ║
71╚════════════════════════════════════════════════════════════╝
72`
73 fmt.Printf(banner, padVersion(version))
74}
75
76// padVersion pads the version string to fit the banner
77func padVersion(version string) string {
78 targetLen := 7
79 if len(version) < targetLen {
80 padding := strings.Repeat(" ", (targetLen-len(version))/2)
81 return padding + version + padding
82 }
83 return version
84}
85
86// RedactPassword redacts passwords from connection strings
87func RedactPassword(connStr string) string {
88 // Handle PostgreSQL URI format: postgresql://user:password@host/db
89 // Pattern: find everything between :// and @ that contains a colon
90 if strings.Contains(connStr, "://") && strings.Contains(connStr, "@") {
91 // Find the credentials section
92 parts := strings.SplitN(connStr, "://", 2)
93 if len(parts) == 2 {
94 scheme := parts[0]
95 remainder := parts[1]
96
97 // Find the @ symbol
98 atIndex := strings.Index(remainder, "@")
99 if atIndex > 0 {
100 credentials := remainder[:atIndex]
101 hostAndDb := remainder[atIndex:]
102
103 // Check if there's a password (look for colon in credentials)
104 colonIndex := strings.Index(credentials, ":")
105 if colonIndex > 0 {
106 username := credentials[:colonIndex]
107 return fmt.Sprintf("%s://%s:***%s", scheme, username, hostAndDb)
108 }
109 }
110 }
111 }
112
113 // Handle key-value format: host=localhost password=secret user=myuser
114 if strings.Contains(connStr, "password=") {
115 parts := strings.Split(connStr, " ")
116 for i, part := range parts {
117 if strings.HasPrefix(part, "password=") {
118 parts[i] = "password=***"
119 }
120 }
121 return strings.Join(parts, " ")
122 }
123
124 return connStr
125}
126
127// PrintConfig prints configuration summary
128func PrintConfig(items map[string]string) {
129 Info("=== Configuration ===")
130 maxKeyLen := 0
131 for key := range items {
132 if len(key) > maxKeyLen {
133 maxKeyLen = len(key)
134 }
135 }
136
137 for key, value := range items {
138 padding := strings.Repeat(" ", maxKeyLen-len(key))
139
140 // Redact database connection strings
141 displayValue := value
142 if strings.Contains(key, "Database Path") || strings.Contains(key, "Connection") || strings.Contains(strings.ToLower(key), "password") {
143 displayValue = RedactPassword(value)
144 }
145
146 fmt.Printf(" %s:%s %s\n", key, padding, displayValue)
147 }
148 Info("====================")
149}