@@ -97,6 +97,145 @@ func TestLogger(t *testing.T) {
9797 }
9898}
9999
100+ func TestLoggerRedaction (t * testing.T ) {
101+ tests := []struct {
102+ name string
103+ rules map [string ]string
104+ message string
105+ wantContains string
106+ wantNotContain string
107+ }{
108+ {
109+ name : "success - redact password" ,
110+ rules : map [string ]string {
111+ "password:" : "***REDACTED***" ,
112+ },
113+ message : "User logged in with password:mysecretpass123" ,
114+ wantContains : "password:***REDACTED***" ,
115+ wantNotContain : "mysecretpass123" ,
116+ },
117+ {
118+ name : "success - redact credit card" ,
119+ rules : map [string ]string {
120+ "credit_card=" : "***REDACTED***" ,
121+ },
122+ message : "Payment processed with credit_card=1234-5678-9876-5432" ,
123+ wantContains : "credit_card=***REDACTED***" ,
124+ wantNotContain : "1234-5678-9876-5432" ,
125+ },
126+ {
127+ name : "success - redact multiple fields" ,
128+ rules : map [string ]string {
129+ "password:" : "***REDACTED***" ,
130+ "email=" : "***REDACTED***" ,
131+ "credit_card=" : "***REDACTED***" ,
132+ },
133+ message :
"User [email protected] logged in with password:secret123" ,
134+ wantContains : "email=***REDACTED***" ,
135+ wantNotContain :
"[email protected] " ,
136+ },
137+ {
138+ name : "success - no redaction without rules" ,
139+ rules : map [string ]string {},
140+ message : "User logged in with password:secret" ,
141+ wantContains : "password:secret" ,
142+ wantNotContain : "REDACTED" ,
143+ },
144+ }
145+
146+ for _ , tt := range tests {
147+ t .Run (tt .name , func (t * testing.T ) {
148+ buffer := & bytes.Buffer {}
149+ logger := logging .NewLogger ("Test" , logging .INFO , buffer )
150+ logger .SetRedactionRules (tt .rules )
151+
152+ logger .Info (tt .message )
153+
154+ output := buffer .String ()
155+ if ! strings .Contains (output , tt .wantContains ) {
156+ t .Errorf ("Expected output to contain '%v', got: %v" , tt .wantContains , output )
157+ }
158+ if tt .wantNotContain != "" && strings .Contains (output , tt .wantNotContain ) {
159+ t .Errorf ("Expected output NOT to contain '%v', got: %v" , tt .wantNotContain , output )
160+ }
161+ })
162+ }
163+ }
164+
165+ func TestLoggerRedactionRegex (t * testing.T ) {
166+ tests := []struct {
167+ name string
168+ patterns map [string ]string
169+ message string
170+ wantContains string
171+ wantNotContain string
172+ wantErr bool
173+ }{
174+ {
175+ name : "success - redact email with regex" ,
176+ patterns : map [string ]string {
177+ `\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Z|a-z]{2,}\b` : "[EMAIL REDACTED]" ,
178+ },
179+ message :
"Contact us at [email protected] for help" ,
180+ wantContains : "[EMAIL REDACTED]" ,
181+ wantNotContain :
"[email protected] " ,
182+ },
183+ {
184+ name : "success - redact credit card numbers" ,
185+ patterns : map [string ]string {
186+ `\b\d{4}-\d{4}-\d{4}-\d{4}\b` : "[CARD REDACTED]" ,
187+ },
188+ message : "Card number: 1234-5678-9012-3456" ,
189+ wantContains : "[CARD REDACTED]" ,
190+ wantNotContain : "1234-5678-9012-3456" ,
191+ },
192+ {
193+ name : "success - redact phone numbers" ,
194+ patterns : map [string ]string {
195+ `\b\d{3}-\d{3}-\d{4}\b` : "[PHONE REDACTED]" ,
196+ },
197+ message : "Call me at 555-123-4567" ,
198+ wantContains : "[PHONE REDACTED]" ,
199+ wantNotContain : "555-123-4567" ,
200+ },
201+ {
202+ name : "error - invalid regex pattern" ,
203+ patterns : map [string ]string {
204+ `[invalid(regex` : "REDACTED" ,
205+ },
206+ message : "test message" ,
207+ wantErr : true ,
208+ },
209+ }
210+
211+ for _ , tt := range tests {
212+ t .Run (tt .name , func (t * testing.T ) {
213+ buffer := & bytes.Buffer {}
214+ logger := logging .NewLogger ("Test" , logging .INFO , buffer )
215+
216+ err := logger .SetRedactionRegex (tt .patterns )
217+ if (err != nil ) != tt .wantErr {
218+ t .Errorf ("SetRedactionRegex() error = %v, wantErr %v" , err , tt .wantErr )
219+ return
220+ }
221+
222+ if tt .wantErr {
223+ return
224+ }
225+
226+ logger .Info (tt .message )
227+
228+ output := buffer .String ()
229+ if ! strings .Contains (output , tt .wantContains ) {
230+ t .Errorf ("Expected output to contain '%v', got: %v" , tt .wantContains , output )
231+ }
232+ if tt .wantNotContain != "" && strings .Contains (output , tt .wantNotContain ) {
233+ t .Errorf ("Expected output NOT to contain '%v', got: %v" , tt .wantNotContain , output )
234+ }
235+ })
236+ }
237+ }
238+
100239// ================================================================================
101240// ### BENCHMARKS
102241// ================================================================================
@@ -108,3 +247,15 @@ func BenchmarkLogger(b *testing.B) {
108247 logger .Info ("This is an info message" )
109248 }
110249}
250+
251+ func BenchmarkLoggerWithRedaction (b * testing.B ) {
252+ logger := logging .NewLogger ("Test" , logging .INFO , io .Discard )
253+ logger .SetRedactionRules (map [string ]string {
254+ "password:" : "***REDACTED***" ,
255+ "email=" : "***REDACTED***" ,
256+ })
257+ b .ReportAllocs ()
258+ for b .Loop () {
259+ logger .
Info (
"User [email protected] logged in with password:secret123" )
260+ }
261+ }
0 commit comments