Skip to content

Commit f0494c8

Browse files
authored
Merge pull request #123 from exceptionless/bug/format-exception
Fixed a bug that was causing a format exception & proxy support
2 parents fdaaa84 + 2a76628 commit f0494c8

File tree

10 files changed

+63
-46
lines changed

10 files changed

+63
-46
lines changed

src/Exceptionless.Tests/Plugins/PluginTests.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -726,7 +726,7 @@ public void VerifyDeduplication() {
726726
var errorPlugin = new ErrorPlugin();
727727

728728
EventPluginContext mergedContext = null;
729-
using (var duplicateCheckerPlugin = new DuplicateCheckerPlugin(TimeSpan.FromMilliseconds(20))) {
729+
using (var duplicateCheckerPlugin = new DuplicateCheckerPlugin(TimeSpan.FromMilliseconds(40))) {
730730
for (int index = 0; index < 10; index++) {
731731
var builder = GetException().ToExceptionless();
732732
var context = new EventPluginContext(client, builder.Target, builder.PluginContextData);
@@ -745,7 +745,7 @@ public void VerifyDeduplication() {
745745
}
746746
}
747747

748-
Thread.Sleep(50);
748+
Thread.Sleep(100);
749749
Assert.Equal(9, mergedContext.Event.Count.GetValueOrDefault());
750750
}
751751

src/Exceptionless.Tests/project.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
}
99
},
1010
"dependencies": {
11-
"BenchmarkDotNet": "0.9.8",
11+
"BenchmarkDotNet": "0.9.9",
1212
"Exceptionless": {
1313
"target": "project"
1414
},

src/Exceptionless/Configuration/ExceptionlessConfiguration.cs

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
using System.Collections.Generic;
44
using System.Diagnostics;
55
using System.Linq;
6+
using System.Net;
67
using System.Reflection;
78
using Exceptionless.Dependency;
89
using Exceptionless.Plugins;
@@ -99,11 +100,6 @@ public string HeartbeatServerUrl {
99100
}
100101
}
101102

102-
/// <summary>
103-
/// Used to identify the client that sent the events to the server.
104-
/// </summary>
105-
public string UserAgent { get; set; }
106-
107103
/// <summary>
108104
/// The API key that will be used when sending events to the server.
109105
/// </summary>
@@ -122,6 +118,16 @@ public string ApiKey {
122118
}
123119
}
124120

121+
/// <summary>
122+
/// Used to identify the client that sent the events to the server.
123+
/// </summary>
124+
public string UserAgent { get; set; }
125+
126+
/// <summary>
127+
/// Ability to set a custom proxy. By default, .NET will use any system or configuration defined proxy settings.
128+
/// </summary>
129+
public IWebProxy Proxy { get; set; }
130+
125131
/// <summary>
126132
/// Whether the client is currently enabled or not. If it is disabled, submitted errors will be discarded and no data will be sent to the server.
127133
/// </summary>

src/Exceptionless/Configuration/SettingsManager.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ public static void CheckVersion(int version, ExceptionlessConfiguration config)
7171
public static void UpdateSettings(ExceptionlessConfiguration config, int? version = null) {
7272
if (config == null || !config.IsValid || !config.Enabled)
7373
return;
74-
74+
7575
try {
7676
if (!version.HasValue || version < 0)
7777
version = GetVersion(config);

src/Exceptionless/ExceptionlessClient.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -203,7 +203,7 @@ public void SubmitEvent(Event ev, ContextData pluginContextData = null) {
203203
_queue.Value.Enqueue(ev);
204204

205205
if (!String.IsNullOrEmpty(ev.ReferenceId)) {
206-
_log.Value.FormattedTrace(typeof(ExceptionlessClient), "Setting last reference id '{0}'", ev.ReferenceId);
206+
_log.Value.FormattedTrace(typeof(ExceptionlessClient), "Setting last reference id: {0}", ev.ReferenceId);
207207
_lastReferenceIdManager.Value.SetLast(ev.ReferenceId);
208208
}
209209

src/Exceptionless/Logging/ExceptionlessLogExtensions.cs

Lines changed: 19 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -11,71 +11,79 @@ public static void Error(this IExceptionlessLog log, Type source, Exception exce
1111
}
1212

1313
public static void FormattedError(this IExceptionlessLog log, Type source, Exception exception, string format, params object[] args) {
14-
log.Error(String.Format(format, args), GetSourceName(source), exception);
14+
log.Error(GetMessage(format, args), GetSourceName(source), exception);
1515
}
1616

1717
public static void FormattedError(this IExceptionlessLog log, Type source, string format, params object[] args) {
18-
log.Error(String.Format(format, args), GetSourceName(source));
18+
log.Error(GetMessage(format, args), GetSourceName(source));
1919
}
2020

2121
public static void Info(this IExceptionlessLog log, Type source, string message) {
2222
log.Info(message, GetSourceName(source));
2323
}
2424

2525
public static void FormattedInfo(this IExceptionlessLog log, Type source, string format, params object[] args) {
26-
log.Info(String.Format(format, args), GetSourceName(source));
26+
log.Info(GetMessage(format, args), GetSourceName(source));
2727
}
2828

2929
public static void Debug(this IExceptionlessLog log, Type source, string message) {
3030
log.Debug(message, GetSourceName(source));
3131
}
3232

3333
public static void FormattedDebug(this IExceptionlessLog log, Type source, string format, params object[] args) {
34-
log.Debug(String.Format(format, args), GetSourceName(source));
34+
log.Debug(GetMessage(format, args), GetSourceName(source));
3535
}
3636

3737
public static void Warn(this IExceptionlessLog log, Type source, string message) {
3838
log.Warn(message, GetSourceName(source));
3939
}
4040

4141
public static void FormattedWarn(this IExceptionlessLog log, Type source, string format, params object[] args) {
42-
log.Warn(String.Format(format, args), GetSourceName(source));
42+
log.Warn(GetMessage(format, args), GetSourceName(source));
4343
}
4444

4545
public static void Trace(this IExceptionlessLog log, Type source, string message) {
4646
log.Trace(message, GetSourceName(source));
4747
}
4848

4949
public static void FormattedTrace(this IExceptionlessLog log, Type source, string format, params object[] args) {
50-
log.Trace(String.Format(format, args), GetSourceName(source));
50+
log.Trace(GetMessage(format, args), GetSourceName(source));
5151
}
5252

5353
public static void Error(this IExceptionlessLog log, Exception exception, string message) {
5454
log.Error(message, exception: exception);
5555
}
5656

5757
public static void FormattedError(this IExceptionlessLog log, Exception exception, string format, params object[] args) {
58-
log.Error(String.Format(format, args), exception: exception);
58+
log.Error(GetMessage(format, args), exception: exception);
5959
}
6060

6161
public static void FormattedError(this IExceptionlessLog log, string format, params object[] args) {
62-
log.Error(String.Format(format, args));
62+
log.Error(GetMessage(format, args));
6363
}
6464

6565
public static void FormattedInfo(this IExceptionlessLog log, string format, params object[] args) {
66-
log.Info(String.Format(format, args));
66+
log.Info(GetMessage(format, args));
6767
}
6868

6969
public static void FormattedDebug(this IExceptionlessLog log, string format, params object[] args) {
70-
log.Debug(String.Format(format, args));
70+
log.Debug(GetMessage(format, args));
7171
}
7272

7373
public static void FormattedWarn(this IExceptionlessLog log, string format, params object[] args) {
74-
log.Warn(String.Format(format, args));
74+
log.Warn(GetMessage(format, args));
7575
}
7676

7777
private static string GetSourceName(Type type) {
7878
return type.Name;
7979
}
80+
81+
private static string GetMessage(string format, params object[] args) {
82+
try {
83+
return String.Format(format, args);
84+
} catch (Exception) {
85+
return format;
86+
}
87+
}
8088
}
8189
}

src/Exceptionless/Plugins/Default/1010_DuplicateCheckerPlugin.cs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -32,29 +32,29 @@ public DuplicateCheckerPlugin(TimeSpan? interval) {
3232
public void Run(EventPluginContext context) {
3333
int hashCode = context.Event.GetHashCode();
3434
int count = context.Event.Count ?? 1;
35-
context.Log.FormattedTrace(typeof(DuplicateCheckerPlugin), String.Concat("Checking event: ", context.Event.Message, " with hash: ", hashCode));
35+
context.Log.FormattedTrace(typeof(DuplicateCheckerPlugin), "Checking event: {0} with hash: {1}", context.Event.Message, hashCode);
3636

3737
lock (_lock) {
3838
// Increment the occurrence count if the event is already queued for submission.
3939
var merged = _mergedEvents.FirstOrDefault(s => s.HashCode == hashCode);
4040
if (merged != null) {
4141
merged.IncrementCount(count);
4242
merged.UpdateDate(context.Event.Date);
43-
context.Log.FormattedInfo(typeof(DuplicateCheckerPlugin), String.Concat("Ignoring duplicate event with hash:", hashCode));
43+
context.Log.FormattedInfo(typeof(DuplicateCheckerPlugin), "Ignoring duplicate event with hash: {0}", hashCode);
4444
context.Cancel = true;
4545
return;
4646
}
4747

4848
DateTimeOffset repeatWindow = DateTimeOffset.UtcNow.Subtract(_interval);
4949
if (_processed.Any(s => s.Item1 == hashCode && s.Item2 >= repeatWindow)) {
50-
context.Log.FormattedInfo(typeof(DuplicateCheckerPlugin), String.Concat("Adding event with hash:", hashCode, " to cache."));
50+
context.Log.FormattedInfo(typeof(DuplicateCheckerPlugin), "Adding event with hash: {0} to cache.", hashCode);
5151
// This event is a duplicate for the first time, lets save it so we can delay it while keeping count
5252
_mergedEvents.Enqueue(new MergedEvent(hashCode, context, count));
5353
context.Cancel = true;
5454
return;
5555
}
5656

57-
context.Log.FormattedInfo(typeof(DuplicateCheckerPlugin), String.Concat("Enqueueing event with hash:", hashCode, " to cache."));
57+
context.Log.FormattedInfo(typeof(DuplicateCheckerPlugin), "Enqueueing event with hash: {0} to cache.", hashCode);
5858
_processed.Enqueue(Tuple.Create(hashCode, DateTimeOffset.UtcNow));
5959

6060
while (_processed.Count > 50)
@@ -116,7 +116,7 @@ public void Resubmit() {
116116
_context.Resolver.GetEventQueue().Enqueue(_context.Event);
117117

118118
if (!String.IsNullOrEmpty(_context.Event.ReferenceId)) {
119-
_context.Log.FormattedTrace(typeof(DuplicateCheckerPlugin), "Setting last reference id '{0}'", _context.Event.ReferenceId);
119+
_context.Log.FormattedTrace(typeof(DuplicateCheckerPlugin), "Setting last reference id: {0}", _context.Event.ReferenceId);
120120
_context.Resolver.GetLastReferenceIdManager().SetLast(_context.Event.ReferenceId);
121121
}
122122

src/Exceptionless/Services/DefaultEnvironmentInfoCollector.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ public DefaultEnvironmentInfoCollector(IExceptionlessLog log) {
2424
public EnvironmentInfo GetEnvironmentInfo() {
2525
if (_environmentInfo != null) {
2626
PopulateThreadInfo(_environmentInfo);
27-
PopulateMemoryInfo(_environmentInfo);
27+
PopulateMemoryInfo(_environmentInfo);
2828
return _environmentInfo;
2929
}
3030

@@ -178,7 +178,7 @@ private void PopulateRuntimeInfo(EnvironmentInfo info) {
178178
#if NETSTANDARD
179179
computerInfo = Microsoft.Extensions.PlatformAbstractions.PlatformServices.Default;
180180
#elif NET45
181-
computerInfo = new Microsoft.VisualBasic.Devices.ComputerInfo();
181+
computerInfo = new Microsoft.VisualBasic.Devices.ComputerInfo();
182182
#endif
183183
} catch (Exception ex) {
184184
_log.FormattedInfo(typeof(DefaultEnvironmentInfoCollector), "Unable to get computer info. Error message: {0}", ex.Message);

src/Exceptionless/Submission/DefaultSubmissionClient.cs

Lines changed: 20 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,10 @@
1515

1616
namespace Exceptionless.Submission {
1717
public class DefaultSubmissionClient : ISubmissionClient, IDisposable {
18-
private readonly HttpClient _client;
18+
private readonly Lazy<HttpClient> _client;
1919

2020
public DefaultSubmissionClient(ExceptionlessConfiguration config) {
21-
_client = CreateHttpClient(config.UserAgent);
21+
_client = new Lazy<HttpClient>(() => CreateHttpClient(config));
2222
}
2323

2424
public SubmissionResponse PostEvents(IEnumerable<Event> events, ExceptionlessConfiguration config, IJsonSerializer serializer) {
@@ -36,8 +36,8 @@ public SubmissionResponse PostEvents(IEnumerable<Event> events, ExceptionlessCon
3636
if (data.Length > 1024 * 4)
3737
content = new GzipContent(content);
3838

39-
_client.AddAuthorizationHeader(config.ApiKey);
40-
response = _client.PostAsync(url, content).ConfigureAwait(false).GetAwaiter().GetResult();
39+
_client.Value.AddAuthorizationHeader(config.ApiKey);
40+
response = _client.Value.PostAsync(url, content).ConfigureAwait(false).GetAwaiter().GetResult();
4141
} catch (Exception ex) {
4242
return new SubmissionResponse(500, message: ex.Message);
4343
}
@@ -48,7 +48,7 @@ public SubmissionResponse PostEvents(IEnumerable<Event> events, ExceptionlessCon
4848

4949
return new SubmissionResponse((int)response.StatusCode, GetResponseMessage(response));
5050
}
51-
51+
5252
public SubmissionResponse PostUserDescription(string referenceId, UserDescription description, ExceptionlessConfiguration config, IJsonSerializer serializer) {
5353
if (!config.IsValid)
5454
return new SubmissionResponse(500, message: "Invalid client configuration settings.");
@@ -64,8 +64,8 @@ public SubmissionResponse PostUserDescription(string referenceId, UserDescriptio
6464
if (data.Length > 1024 * 4)
6565
content = new GzipContent(content);
6666

67-
_client.AddAuthorizationHeader(config.ApiKey);
68-
response = _client.PostAsync(url, content).ConfigureAwait(false).GetAwaiter().GetResult();
67+
_client.Value.AddAuthorizationHeader(config.ApiKey);
68+
response = _client.Value.PostAsync(url, content).ConfigureAwait(false).GetAwaiter().GetResult();
6969
} catch (Exception ex) {
7070
return new SubmissionResponse(500, message: ex.Message);
7171
}
@@ -85,8 +85,8 @@ public SettingsResponse GetSettings(ExceptionlessConfiguration config, int versi
8585

8686
HttpResponseMessage response;
8787
try {
88-
_client.AddAuthorizationHeader(config.ApiKey);
89-
response = _client.GetAsync(url).ConfigureAwait(false).GetAwaiter().GetResult();
88+
_client.Value.AddAuthorizationHeader(config.ApiKey);
89+
response = _client.Value.GetAsync(url).ConfigureAwait(false).GetAwaiter().GetResult();
9090
} catch (Exception ex) {
9191
var message = String.Concat("Unable to retrieve configuration settings. Exception: ", ex.GetMessage());
9292
return new SettingsResponse(false, message: message);
@@ -105,22 +105,22 @@ public SettingsResponse GetSettings(ExceptionlessConfiguration config, int versi
105105
var settings = serializer.Deserialize<ClientConfiguration>(json);
106106
return new SettingsResponse(true, settings.Settings, settings.Version);
107107
}
108-
108+
109109
public void SendHeartbeat(string sessionIdOrUserId, bool closeSession, ExceptionlessConfiguration config) {
110110
if (!config.IsValid)
111111
return;
112112

113113
string url = String.Format("{0}/events/session/heartbeat?id={1}&close={2}", GetHeartbeatServiceEndPoint(config), sessionIdOrUserId, closeSession);
114114
try {
115-
_client.AddAuthorizationHeader(config.ApiKey);
116-
_client.GetAsync(url).ConfigureAwait(false).GetAwaiter().GetResult();
115+
_client.Value.AddAuthorizationHeader(config.ApiKey);
116+
_client.Value.GetAsync(url).ConfigureAwait(false).GetAwaiter().GetResult();
117117
} catch (Exception ex) {
118118
var log = config.Resolver.GetLog();
119119
log.Error(String.Concat("Error submitting heartbeat: ", ex.GetMessage()));
120120
}
121121
}
122122

123-
private HttpClient CreateHttpClient(string userAgent) {
123+
protected virtual HttpClient CreateHttpClient(ExceptionlessConfiguration config) {
124124
#if NET45
125125
var handler = new WebRequestHandler { UseDefaultCredentials = true };
126126
handler.ServerCertificateValidationCallback = delegate { return true; };
@@ -130,17 +130,19 @@ private HttpClient CreateHttpClient(string userAgent) {
130130
//handler.ServerCertificateCustomValidationCallback = delegate { return true; };
131131
#endif
132132
#endif
133-
134133
if (handler.SupportsAutomaticDecompression)
135134
handler.AutomaticDecompression = DecompressionMethods.Deflate | DecompressionMethods.GZip | DecompressionMethods.None;
136135

137136
if (handler.SupportsRedirectConfiguration)
138137
handler.AllowAutoRedirect = true;
139-
138+
139+
if (handler.SupportsProxy && config.Proxy != null)
140+
handler.Proxy = config.Proxy;
141+
140142
var client = new HttpClient(handler, true);
141143
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
142144
client.DefaultRequestHeaders.ExpectContinue = false;
143-
client.DefaultRequestHeaders.UserAgent.ParseAdd(userAgent);
145+
client.DefaultRequestHeaders.UserAgent.ParseAdd(config.UserAgent);
144146

145147
return client;
146148
}
@@ -205,7 +207,8 @@ private Uri GetHeartbeatServiceEndPoint(ExceptionlessConfiguration config) {
205207
}
206208

207209
public void Dispose() {
208-
_client.Dispose();
210+
if (_client.IsValueCreated)
211+
_client.Value.Dispose();
209212
}
210213
}
211214
}

src/Platforms/Exceptionless.NLog/project.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@
4848
"define": [ "NET45" ]
4949
},
5050
"dependencies": {
51-
"NLog": "4.3.6"
51+
"NLog": "4.3.8"
5252
}
5353
}
5454
}

0 commit comments

Comments
 (0)