@@ -65,6 +65,25 @@ void WriteDictionary<TKey, TValue>(
65
65
[ System . Runtime . CompilerServices . CallerLineNumber ] int lineNumber = 0 ,
66
66
[ System . Runtime . CompilerServices . CallerMemberName ] string memberName = "" ) ;
67
67
68
+ /// <summary>
69
+ /// Write the contents of a dictionary that contains sensitive information to the trace writer.
70
+ /// <para/>
71
+ /// Calls <see cref="object.ToString"/> on all keys and values, except keys specified as secret.
72
+ /// </summary>
73
+ /// <param name="dictionary">The dictionary to write.</param>
74
+ /// <param name="secretKeys">Dictionary keys that contain secrets/sensitive information.</param>
75
+ /// <param name="keyComparer">Comparer to use for <paramref name="secretKeys"/>.</param>
76
+ /// <param name="filePath">Path of the file this method is called from.</param>
77
+ /// <param name="lineNumber">Line number of file this method is called from.</param>
78
+ /// <param name="memberName">Name of the member in which this method is called.</param>
79
+ void WriteDictionarySecrets < TKey , TValue > (
80
+ IDictionary < TKey , TValue > dictionary ,
81
+ TKey [ ] secretKeys ,
82
+ IEqualityComparer < TKey > keyComparer = null ,
83
+ [ System . Runtime . CompilerServices . CallerFilePath ] string filePath = "" ,
84
+ [ System . Runtime . CompilerServices . CallerLineNumber ] int lineNumber = 0 ,
85
+ [ System . Runtime . CompilerServices . CallerMemberName ] string memberName = "" ) ;
86
+
68
87
/// <summary>
69
88
/// Writes a message to the trace writer followed by a line terminator.
70
89
/// </summary>
@@ -101,6 +120,8 @@ void WriteLineSecrets(
101
120
102
121
public class Trace : ITrace , IDisposable
103
122
{
123
+ private const string SecretMask = "********" ;
124
+
104
125
private readonly object _writersLock = new object ( ) ;
105
126
private readonly List < TextWriter > _writers = new List < TextWriter > ( ) ;
106
127
@@ -188,6 +209,30 @@ public void WriteDictionary<TKey, TValue>(
188
209
}
189
210
}
190
211
212
+ [ System . Diagnostics . CodeAnalysis . SuppressMessage ( "Microsoft.Design" , "CA1026:DefaultParametersShouldNotBeUsed" ) ]
213
+ public void WriteDictionarySecrets < TKey , TValue > (
214
+ IDictionary < TKey , TValue > dictionary ,
215
+ TKey [ ] secretKeys ,
216
+ IEqualityComparer < TKey > keyComparer = null ,
217
+ [ System . Runtime . CompilerServices . CallerFilePath ] string filePath = "" ,
218
+ [ System . Runtime . CompilerServices . CallerLineNumber ] int lineNumber = 0 ,
219
+ [ System . Runtime . CompilerServices . CallerMemberName ] string memberName = "" )
220
+ {
221
+ foreach ( KeyValuePair < TKey , TValue > entry in dictionary )
222
+ {
223
+ bool isSecretEntry = ! ( secretKeys is null ) &&
224
+ secretKeys . Contains ( entry . Key , keyComparer ?? EqualityComparer < TKey > . Default ) ;
225
+ if ( isSecretEntry && ! this . IsSecretTracingEnabled )
226
+ {
227
+ WriteLine ( $ "\t { entry . Key } ={ SecretMask } ", filePath , lineNumber , memberName ) ;
228
+ }
229
+ else
230
+ {
231
+ WriteLine ( $ "\t { entry . Key } ={ entry . Value } ", filePath , lineNumber , memberName ) ;
232
+ }
233
+ }
234
+ }
235
+
191
236
[ System . Diagnostics . CodeAnalysis . SuppressMessage ( "Microsoft.Design" , "CA1026:DefaultParametersShouldNotBeUsed" ) ]
192
237
public void WriteLine (
193
238
string message ,
@@ -227,7 +272,7 @@ public void WriteLineSecrets(
227
272
{
228
273
string message = this . IsSecretTracingEnabled
229
274
? string . Format ( format , secrets )
230
- : string . Format ( format , secrets . Select ( _ => ( object ) "********" ) . ToArray ( ) ) ;
275
+ : string . Format ( format , secrets . Select ( _ => ( object ) SecretMask ) . ToArray ( ) ) ;
231
276
232
277
WriteLine ( message , filePath , lineNumber , memberName ) ;
233
278
}
0 commit comments