1414
1515namespace NuGetGallery . Infrastructure
1616{
17- public class ErrorEntity : ITableEntity
17+ public class ErrorEntity : ITableEntity
18+ {
19+ public Error Error { get ; set ; }
20+
21+ string ITableEntity . ETag
22+ {
23+ get ;
24+ set ;
25+ }
26+
27+ string ITableEntity . PartitionKey
1828 {
19- public Error Error { get ; set ; }
29+ get ;
30+ set ;
31+ }
32+
33+ string ITableEntity . RowKey
34+ {
35+ get ;
36+ set ;
37+ }
38+
39+ DateTimeOffset ITableEntity . Timestamp
40+ {
41+ get ;
42+ set ;
43+ }
2044
21- string ITableEntity . ETag
45+ public long LogicalIndex
46+ {
47+ get
2248 {
23- get ;
24- set ;
49+ return AzureEntityList < ErrorEntity > . GetLogicalIndex ( this ) ;
2550 }
51+ }
52+
53+ public ErrorEntity ( ) { }
54+
55+ public ErrorEntity ( Error error )
56+ {
57+ Error = error ;
58+ }
59+
60+ void ITableEntity . ReadEntity ( IDictionary < string , EntityProperty > properties , Microsoft . WindowsAzure . Storage . OperationContext operationContext )
61+ {
62+ // This can occasionally fail because someone didn't finish creating the entity yet.
2663
27- string ITableEntity . PartitionKey
64+ EntityProperty value ;
65+ if ( properties . TryGetValue ( "SerializedError" , out value ) )
2866 {
29- get ;
30- set ;
67+ Error = ErrorXml . DecodeString ( value . StringValue ) ;
3168 }
32-
33- string ITableEntity . RowKey
69+ else
3470 {
35- get ;
36- set ;
71+ Error = new Error
72+ {
73+ ApplicationName = "TableErrorLog" ,
74+ StatusCode = 999 ,
75+ HostName = Environment . MachineName ,
76+ Time = DateTime . UtcNow ,
77+ Type = typeof ( Exception ) . FullName ,
78+ Detail = "Error Log Entry is Corrupted/Missing in Table Store"
79+ } ;
80+
81+ return ;
3782 }
3883
39- DateTimeOffset ITableEntity . Timestamp
84+ if ( properties . TryGetValue ( "Detail" , out value ) )
4085 {
41- get ;
42- set ;
86+ Error . Detail = value . StringValue ;
4387 }
4488
45- public long LogicalIndex
89+ if ( properties . TryGetValue ( "WebHostHtmlMessage" , out value ) )
4690 {
47- get
48- {
49- return AzureEntityList < ErrorEntity > . GetLogicalIndex ( this ) ;
50- }
91+ Error . WebHostHtmlMessage = value . StringValue ;
5192 }
93+ }
5294
53- public ErrorEntity ( ) { }
95+ IDictionary < string , EntityProperty > ITableEntity . WriteEntity ( OperationContext operationContext )
96+ {
97+ // Table storage has a limitation on property lengths - 64KiB.
98+ // Strings will be encoded as UTF-16, apparently?
99+
100+ const int MaxChars = 32 * 1000 ;
54101
55- public ErrorEntity ( Error error )
102+ var detail = Error . Detail ;
103+ if ( detail . Length > MaxChars )
56104 {
57- Error = error ;
105+ detail = detail . Substring ( 0 , MaxChars ) ;
58106 }
59107
60- void ITableEntity . ReadEntity ( IDictionary < string , EntityProperty > properties , Microsoft . WindowsAzure . Storage . OperationContext operationContext )
108+ var htmlMessage = Error . WebHostHtmlMessage ;
109+ if ( htmlMessage . Length > MaxChars )
61110 {
62- // This can occasionally fail because someone didn't finish creating the entity yet.
111+ htmlMessage = htmlMessage . Substring ( 0 , MaxChars ) ;
112+ }
63113
64- EntityProperty value ;
65- if ( properties . TryGetValue ( "SerializedError" , out value ) )
66- {
67- Error = ErrorXml . DecodeString ( value . StringValue ) ;
68- }
69- else
70- {
71- Error = new Error
114+ Error . Detail = null ;
115+ Error . WebHostHtmlMessage = null ;
116+ string serializedError = ErrorXml . EncodeString ( Error ) ;
117+
118+ if ( serializedError . Length > MaxChars )
119+ {
120+ serializedError = ErrorXml . EncodeString (
121+ new Error
72122 {
73123 ApplicationName = "TableErrorLog" ,
74- StatusCode = 999 ,
124+ StatusCode = 888 ,
75125 HostName = Environment . MachineName ,
76126 Time = DateTime . UtcNow ,
77- Type = typeof ( Exception ) . FullName ,
78- Detail = "Error Log Entry is Corrupted/Missing in Table Store"
79- } ;
80-
81- return ;
82- }
83-
84- if ( properties . TryGetValue ( "Detail" , out value ) )
85- {
86- Error . Detail = value . StringValue ;
87- }
88-
89- if ( properties . TryGetValue ( "WebHostHtmlMessage" , out value ) )
90- {
91- Error . WebHostHtmlMessage = value . StringValue ;
92- }
127+ Detail = "Error Log Entry Will Not Fit In Table Store: " + serializedError . Substring ( 0 , 4000 )
128+ } ) ;
93129 }
94130
95- IDictionary < string , EntityProperty > ITableEntity . WriteEntity ( OperationContext operationContext )
96- {
97- // Table storage has a limitation on property lengths - 64KiB.
98- // Strings will be encoded as UTF-16, apparently?
99-
100- const int MaxChars = 32 * 1000 ;
101-
102- var detail = Error . Detail ;
103- if ( detail . Length > MaxChars )
104- {
105- detail = detail . Substring ( 0 , MaxChars ) ;
106- }
107-
108- var htmlMessage = Error . WebHostHtmlMessage ;
109- if ( htmlMessage . Length > MaxChars )
110- {
111- htmlMessage = htmlMessage . Substring ( 0 , MaxChars ) ;
112- }
113-
114- Error . Detail = null ;
115- Error . WebHostHtmlMessage = null ;
116- string serializedError = ErrorXml . EncodeString ( Error ) ;
117-
118- if ( serializedError . Length > MaxChars )
119- {
120- serializedError = ErrorXml . EncodeString (
121- new Error
122- {
123- ApplicationName = "TableErrorLog" ,
124- StatusCode = 888 ,
125- HostName = Environment . MachineName ,
126- Time = DateTime . UtcNow ,
127- Detail = "Error Log Entry Will Not Fit In Table Store: " + serializedError . Substring ( 0 , 4000 )
128- } ) ;
129- }
130-
131- return new Dictionary < string , EntityProperty >
131+ return new Dictionary < string , EntityProperty >
132132 {
133133 { "SerializedError" , EntityProperty . GeneratePropertyForString ( serializedError ) } ,
134134 { "Detail" , EntityProperty . GeneratePropertyForString ( detail ) } ,
135135 { "WebHostHtmlMessage" , EntityProperty . GeneratePropertyForString ( htmlMessage ) } ,
136136 } ;
137- }
138137 }
138+ }
139139
140- public class TableErrorLog : ErrorLog
140+ public class TableErrorLog : ErrorLog
141+ {
142+ public const string TableName = "ElmahErrors" ;
143+
144+ private readonly string _connectionString ;
145+ private readonly AzureEntityList < ErrorEntity > _entityList ;
146+
147+ public TableErrorLog ( string connectionString , bool readAccessGeoRedundant )
141148 {
142- public const string TableName = "ElmahErrors" ;
149+ _connectionString = connectionString ;
150+ _entityList = new AzureEntityList < ErrorEntity > ( connectionString , TableName , readAccessGeoRedundant ) ;
151+ }
143152
144- private readonly string _connectionString ;
145- private readonly AzureEntityList < ErrorEntity > _entityList ;
153+ public override ErrorLogEntry GetError ( string id )
154+ {
155+ long pos = Int64 . Parse ( id , CultureInfo . InvariantCulture ) ;
156+ var error = _entityList [ pos ] ;
157+ Debug . Assert ( id == pos . ToString ( CultureInfo . InvariantCulture ) ) ;
158+ return new ErrorLogEntry ( this , id , error . Error ) ;
159+ }
146160
147- public TableErrorLog ( string connectionString , bool readAccessGeoRedundant )
161+ public override int GetErrors ( int pageIndex , int pageSize , IList errorEntryList )
162+ {
163+ // A little math is required since the AzureEntityList is in ascending order
164+ // And we want to retrieve entries in descending order
165+ long queryOffset = _entityList . LongCount - ( ( pageIndex + 1 ) * pageSize ) ;
166+ if ( queryOffset < 0 )
148167 {
149- _connectionString = connectionString ;
150- _entityList = new AzureEntityList < ErrorEntity > ( connectionString , TableName , readAccessGeoRedundant ) ;
168+ pageSize += ( int ) queryOffset ;
169+ queryOffset = 0 ;
151170 }
152171
153- public override ErrorLogEntry GetError ( string id )
172+ // And since that range was in ascending, flip it to descending.
173+ var results = _entityList . GetRange ( queryOffset , pageSize ) . Reverse ( ) ;
174+ foreach ( var error in results )
154175 {
155- long pos = Int64 . Parse ( id , CultureInfo . InvariantCulture ) ;
156- var error = _entityList [ pos ] ;
157- Debug . Assert ( id == pos . ToString ( CultureInfo . InvariantCulture ) ) ;
158- return new ErrorLogEntry ( this , id , error . Error ) ;
176+ string id = error . LogicalIndex . ToString ( CultureInfo . InvariantCulture ) ;
177+ errorEntryList . Add ( new ErrorLogEntry ( this , id , error . Error ) ) ;
159178 }
160179
161- public override int GetErrors ( int pageIndex , int pageSize , IList errorEntryList )
162- {
163- // A little math is required since the AzureEntityList is in ascending order
164- // And we want to retrieve entries in descending order
165- long queryOffset = _entityList . LongCount - ( ( pageIndex + 1 ) * pageSize ) ;
166- if ( queryOffset < 0 )
167- {
168- pageSize += ( int ) queryOffset ;
169- queryOffset = 0 ;
170- }
171-
172- // And since that range was in ascending, flip it to descending.
173- var results = _entityList . GetRange ( queryOffset , pageSize ) . Reverse ( ) ;
174- foreach ( var error in results )
175- {
176- string id = error . LogicalIndex . ToString ( CultureInfo . InvariantCulture ) ;
177- errorEntryList . Add ( new ErrorLogEntry ( this , id , error . Error ) ) ;
178- }
180+ return _entityList . Count ;
181+ }
179182
180- return _entityList . Count ;
181- }
183+ public override string Log ( Error error )
184+ {
185+ Obfuscate ( error ) ;
186+ var entity = new ErrorEntity ( error ) ;
187+ long pos = _entityList . Add ( entity ) ;
188+ return pos . ToString ( CultureInfo . InvariantCulture ) ;
189+ }
182190
183- public override string Log ( Error error )
191+ private void Obfuscate ( Error error )
192+ {
193+ error . User = string . Empty ;
194+ if ( error . Form != null )
184195 {
185- Obfuscate ( error ) ;
186- var entity = new ErrorEntity ( error ) ;
187- long pos = _entityList . Add ( entity ) ;
188- return pos . ToString ( CultureInfo . InvariantCulture ) ;
196+ error . Form . Clear ( ) ;
189197 }
190198
191- private void Obfuscate ( Error error )
199+ //ServerVariables overrides requiring context from the http request should be handled in NuGetGallery.QuietLog
200+ var elmahException = error . Exception as ElmahException ;
201+ if ( elmahException != null )
192202 {
193- error . User = string . Empty ;
194- if ( error . Form != null )
203+ var piiServerVaribles = elmahException . ServerVariables ;
204+ foreach ( var key in piiServerVaribles . Keys )
195205 {
196- error . Form . Clear ( ) ;
206+ error . ServerVariables [ key ] = piiServerVaribles [ key ] ;
197207 }
208+ }
198209
199- //ServerVariables overrides requiring context from the http request should be handled in NuGetGallery.QuietLog
200- var elmahException = error . Exception as ElmahException ;
201- if ( elmahException != null )
202- {
203- var piiServerVaribles = elmahException . ServerVariables ;
204- foreach ( var key in piiServerVaribles . Keys )
205- {
206- error . ServerVariables [ key ] = piiServerVaribles [ key ] ;
207- }
208- }
210+ error . ServerVariables [ "ALL_HTTP" ] = string . Empty ;
211+ error . ServerVariables [ "ALL_RAW" ] = string . Empty ;
209212
210- error . ServerVariables [ "AUTH_USER" ] = string . Empty ;
211- error . ServerVariables [ "LOGON_USER" ] = string . Empty ;
212- error . ServerVariables [ "REMOTE_USER" ] = string . Empty ;
213+ error . ServerVariables [ "AUTH_USER" ] = string . Empty ;
214+ error . ServerVariables [ "LOGON_USER" ] = string . Empty ;
215+ error . ServerVariables [ "REMOTE_USER" ] = string . Empty ;
213216
214- error . ServerVariables [ "REMOTE_ADDR" ] = Obfuscator . ObfuscateIp ( error . ServerVariables [ "REMOTE_ADDR" ] ) ;
215- error . ServerVariables [ "REMOTE_HOST" ] = Obfuscator . ObfuscateIp ( error . ServerVariables [ "REMOTE_HOST" ] ) ;
216- error . ServerVariables [ "LOCAL_ADDR" ] = Obfuscator . ObfuscateIp ( error . ServerVariables [ "LOCAL_ADDR" ] ) ;
217- }
217+ error . ServerVariables [ "REMOTE_ADDR" ] = Obfuscator . ObfuscateIp ( error . ServerVariables [ "REMOTE_ADDR" ] ) ;
218+ error . ServerVariables [ "REMOTE_HOST" ] = Obfuscator . ObfuscateIp ( error . ServerVariables [ "REMOTE_HOST" ] ) ;
219+ error . ServerVariables [ "LOCAL_ADDR" ] = Obfuscator . ObfuscateIp ( error . ServerVariables [ "LOCAL_ADDR" ] ) ;
220+
221+ error . ServerVariables [ "HTTP_X_NUGET_APIKEY" ] = string . Empty ;
222+
223+ var forwardedIps = error . ServerVariables [ "HTTP_X_FORWARDED_FOR" ] . Split ( ',' ) ;
224+ var obfuscatedIps = forwardedIps . Select ( Obfuscator . ObfuscateIp ) ;
225+
226+ error . ServerVariables [ "HTTP_X_FORWARDED_FOR" ] = string . Join ( "," , obfuscatedIps ) ;
218227 }
228+ }
219229}
0 commit comments