● Notice //GitHub (@shehzade) is temporarily suspended pending an automated false-positive review. All tools are hosted on this Code Mirror and available on request (contact); GitHub links will return once reinstated.
PUBLIC MIRRORGo v1.0

Multi-protocol network egress assessment and DLP verification framework featuring automated L4 sweeps, corporate proxy traversal, and covert protocol smuggling across 20+ channels.

$ git clone https://shehzade.io/repos/contraband.git Copy
Source ZIP (1.93 MB)
Code 174 Commits 1
contraband / pkg / common / logger.go
← Back to directory
246 lines · 6.3 KB
Raw
1package common
2
3import (
4 "encoding/json"
5 "fmt"
6 "io"
7 "os"
8 "sync"
9 "time"
10)
11
12type LogLevel int
13
14const (
15 LogLevelDebug LogLevel = iota
16 LogLevelInfo
17 LogLevelSuccess
18 LogLevelWarn
19 LogLevelError
20 LogLevelFatal
21)
22
23func (l LogLevel) String() string {
24 switch l {
25 case LogLevelDebug:
26 return "DEBUG"
27 case LogLevelInfo:
28 return "INFO"
29 case LogLevelSuccess:
30 return "SUCCESS"
31 case LogLevelWarn:
32 return "WARN"
33 case LogLevelError:
34 return "ERROR"
35 case LogLevelFatal:
36 return "FATAL"
37 default:
38 return "UNKNOWN"
39 }
40}
41
42type LogMode int
43
44const (
45 LogModeTerminal LogMode = iota
46 LogModeJSON
47)
48
49// ANSI Color Codes
50const (
51 ansiReset = "\033[0m"
52 ansiBold = "\033[1m"
53 ansiRed = "\033[1;31m"
54 ansiGreen = "\033[1;32m"
55 ansiYellow = "\033[1;33m"
56 ansiCyan = "\033[1;36m"
57 ansiMagenta = "\033[1;35m"
58 ansiDim = "\033[2m"
59)
60
61// Logger is the core logging interface for Contraband
62type Logger interface {
63 Debug(msg string)
64 Debugf(format string, args ...any)
65 Info(msg string)
66 Infof(format string, args ...any)
67 Success(msg string)
68 Successf(format string, args ...any)
69 Warn(msg string)
70 Warnf(format string, args ...any)
71 Error(msg string)
72 Errorf(format string, args ...any)
73 Fatal(msg string)
74 Fatalf(format string, args ...any)
75 WithField(key string, val any) Logger
76 WithFields(fields map[string]any) Logger
77 SetLevel(level LogLevel)
78 SetMode(mode LogMode)
79 SetOutput(w io.Writer)
80 SetNoColor(noColor bool)
81}
82
83// JSONLogEntry represents a serialized JSON log line
84type JSONLogEntry struct {
85 Timestamp time.Time `json:"timestamp"`
86 Level string `json:"level"`
87 Indicator string `json:"indicator"`
88 Message string `json:"message"`
89 Fields map[string]any `json:"fields,omitempty"`
90}
91
92type appLogger struct {
93 mu sync.Mutex
94 out io.Writer
95 level LogLevel
96 mode LogMode
97 noColor bool
98 fields map[string]any
99 // exitFunc allows mocking os.Exit in tests if needed
100 exitFunc func(code int)
101}
102
103// NewLogger creates a new configured Logger instance
104func NewLogger(out io.Writer, level LogLevel, mode LogMode) Logger {
105 if out == nil {
106 out = os.Stdout
107 }
108 noColor := os.Getenv("NO_COLOR") != ""
109 return &appLogger{
110 out: out,
111 level: level,
112 mode: mode,
113 noColor: noColor,
114 fields: make(map[string]any),
115 exitFunc: os.Exit,
116 }
117}
118
119var (
120 defaultLoggerMu sync.RWMutex
121 defaultLogger = NewLogger(os.Stdout, LogLevelInfo, LogModeTerminal)
122)
123
124// Global helper accessors
125func GetLogger() Logger {
126 defaultLoggerMu.RLock()
127 defer defaultLoggerMu.RUnlock()
128 return defaultLogger
129}
130func SetGlobalLogger(l Logger) { defaultLoggerMu.Lock(); defaultLogger = l; defaultLoggerMu.Unlock() }
131func Debugf(format string, args ...any) { defaultLogger.Debugf(format, args...) }
132func Infof(format string, args ...any) { defaultLogger.Infof(format, args...) }
133func Successf(format string, args ...any) { defaultLogger.Successf(format, args...) }
134func Warnf(format string, args ...any) { defaultLogger.Warnf(format, args...) }
135func Errorf(format string, args ...any) { defaultLogger.Errorf(format, args...) }
136func Fatalf(format string, args ...any) { defaultLogger.Fatalf(format, args...) }
137
138func (l *appLogger) SetLevel(level LogLevel) { l.mu.Lock(); l.level = level; l.mu.Unlock() }
139func (l *appLogger) SetMode(mode LogMode) { l.mu.Lock(); l.mode = mode; l.mu.Unlock() }
140func (l *appLogger) SetOutput(w io.Writer) { l.mu.Lock(); l.out = w; l.mu.Unlock() }
141func (l *appLogger) SetNoColor(noColor bool) { l.mu.Lock(); l.noColor = noColor; l.mu.Unlock() }
142
143func (l *appLogger) WithField(key string, val any) Logger {
144 return l.WithFields(map[string]any{key: val})
145}
146
147func (l *appLogger) WithFields(fields map[string]any) Logger {
148 l.mu.Lock()
149 defer l.mu.Unlock()
150 newFields := make(map[string]any, len(l.fields)+len(fields))
151 for k, v := range l.fields {
152 newFields[k] = v
153 }
154 for k, v := range fields {
155 newFields[k] = v
156 }
157 return &appLogger{
158 out: l.out,
159 level: l.level,
160 mode: l.mode,
161 noColor: l.noColor,
162 fields: newFields,
163 exitFunc: l.exitFunc,
164 }
165}
166
167func (l *appLogger) log(level LogLevel, msg string) {
168 l.mu.Lock()
169 defer l.mu.Unlock()
170
171 if level < l.level {
172 return
173 }
174
175 now := time.Now().UTC()
176
177 var indicator, colorCode string
178 switch level {
179 case LogLevelDebug:
180 indicator = "[?]"
181 colorCode = ansiMagenta
182 case LogLevelInfo:
183 indicator = "[*]"
184 colorCode = ansiCyan
185 case LogLevelSuccess:
186 indicator = "[+]"
187 colorCode = ansiGreen
188 case LogLevelWarn:
189 indicator = "[!]"
190 colorCode = ansiYellow
191 case LogLevelError:
192 indicator = "[-]"
193 colorCode = ansiRed
194 case LogLevelFatal:
195 indicator = "[-]"
196 colorCode = ansiRed
197 default:
198 indicator = "[*]"
199 colorCode = ansiCyan
200 }
201
202 if l.mode == LogModeJSON {
203 entry := JSONLogEntry{
204 Timestamp: now,
205 Level: level.String(),
206 Indicator: indicator,
207 Message: msg,
208 Fields: l.fields,
209 }
210 data, _ := json.Marshal(entry)
211 fmt.Fprintln(l.out, string(data))
212 } else {
213 prefix := indicator
214 if !l.noColor {
215 prefix = fmt.Sprintf("%s%s%s", colorCode, indicator, ansiReset)
216 }
217 timeStr := now.Format("15:04:05")
218 if !l.noColor {
219 timeStr = fmt.Sprintf("%s%s%s", ansiDim, timeStr, ansiReset)
220 }
221 fmt.Fprintf(l.out, "%s %s %s\n", timeStr, prefix, msg)
222 }
223
224 if level == LogLevelFatal && l.exitFunc != nil {
225 l.exitFunc(1)
226 }
227}
228
229func (l *appLogger) Debug(msg string) { l.log(LogLevelDebug, msg) }
230func (l *appLogger) Debugf(format string, a ...any) { l.log(LogLevelDebug, fmt.Sprintf(format, a...)) }
231func (l *appLogger) Info(msg string) { l.log(LogLevelInfo, msg) }
232func (l *appLogger) Infof(format string, a ...any) { l.log(LogLevelInfo, fmt.Sprintf(format, a...)) }
233func (l *appLogger) Success(msg string) { l.log(LogLevelSuccess, msg) }
234func (l *appLogger) Successf(format string, a ...any) {
235 l.log(LogLevelSuccess, fmt.Sprintf(format, a...))
236}
237func (l *appLogger) Warn(msg string) { l.log(LogLevelWarn, msg) }
238func (l *appLogger) Warnf(format string, a ...any) { l.log(LogLevelWarn, fmt.Sprintf(format, a...)) }
239func (l *appLogger) Error(msg string) { l.log(LogLevelError, msg) }
240func (l *appLogger) Errorf(format string, a ...any) {
241 l.log(LogLevelError, fmt.Sprintf(format, a...))
242}
243func (l *appLogger) Fatal(msg string) { l.log(LogLevelFatal, msg) }
244func (l *appLogger) Fatalf(format string, a ...any) {
245 l.log(LogLevelFatal, fmt.Sprintf(format, a...))
246}