/// <summary> /// Logs response from Airbrake to the file. /// </summary> public static void LogResponse(string logFile, AirbrakeResponse response) { if (response == null) { return; } #if NETSTANDARD1_4 using (var writer = File.AppendText(logFile)) { lock (logResponseLocker) { writer.WriteLineAsync( $"[{DateTime.UtcNow.ToString("o", CultureInfo.InvariantCulture)}] {response.Status} {response.Id} {response.Url}"); } } #else using (var writer = TextWriter.Synchronized(File.AppendText(logFile))) writer.WriteLineAsync( $"[{DateTime.UtcNow.ToString("o", CultureInfo.InvariantCulture)}] {response.Status} {response.Id} {response.Url}"); #endif }
/// <summary> /// Instantiates a new instance of the <see cref="NotifyCompletedEventArgs"/> class. /// </summary> public NotifyCompletedEventArgs(AirbrakeResponse response, Exception error, bool cancelled, object state) : base(error, cancelled, state) { Result = response; }
public Task <AirbrakeResponse> NotifyAsync(Exception exception, IHttpContext context = null) { if (string.IsNullOrEmpty(config.ProjectId)) { throw new Exception("Project Id is required"); } if (string.IsNullOrEmpty(config.ProjectKey)) { throw new Exception("Project Key is required"); } // Task-based Asynchronous Pattern (https://msdn.microsoft.com/en-us/library/hh873177.aspx) var tcs = new TaskCompletionSource <AirbrakeResponse>(); try { if (Utils.IsIgnoredEnvironment(config.Environment, config.IgnoreEnvironments)) { var response = new AirbrakeResponse { Status = RequestStatus.Ignored }; tcs.SetResult(response); return(tcs.Task); } var noticeBuilder = new NoticeBuilder(); noticeBuilder.SetErrorEntries(exception); noticeBuilder.SetConfigurationContext(config); if (context != null) { noticeBuilder.SetHttpContext(context, config); } #if NET45 noticeBuilder.SetEnvironmentContext(Dns.GetHostName(), Environment.OSVersion.VersionString, "C#/NET45"); #elif NETSTANDARD1_4 // TODO: check https://github.com/dotnet/corefx/issues/4306 for "Environment.MachineName" noticeBuilder.SetEnvironmentContext("", RuntimeInformation.OSDescription, "C#/NETCORE"); #endif var notice = noticeBuilder.ToNotice(); if (filters.Count > 0) { notice = Utils.ApplyFilters(notice, filters); } if (notice == null) { var response = new AirbrakeResponse { Status = RequestStatus.Ignored }; tcs.SetResult(response); return(tcs.Task); } var request = httpRequestHandler.Get(); request.ContentType = "application/json"; request.Accept = "application/json"; request.Method = "POST"; request.GetRequestStreamAsync().ContinueWith(requestStreamTask => { if (requestStreamTask.IsFaulted) { if (requestStreamTask.Exception != null) { tcs.SetException(requestStreamTask.Exception.InnerExceptions); } } else if (requestStreamTask.IsCanceled) { tcs.SetCanceled(); } else { using (var requestStream = requestStreamTask.Result) using (var requestWriter = new StreamWriter(requestStream)) requestWriter.Write(NoticeBuilder.ToJsonString(notice)); request.GetResponseAsync().ContinueWith(responseTask => { if (responseTask.IsFaulted) { if (responseTask.Exception != null) { tcs.SetException(responseTask.Exception.InnerExceptions); } } else if (responseTask.IsCanceled) { tcs.SetCanceled(); } else { IHttpResponse httpResponse = null; try { httpResponse = responseTask.Result; using (var responseStream = httpResponse.GetResponseStream()) using (var responseReader = new StreamReader(responseStream)) { var airbrakeResponse = JsonConvert.DeserializeObject <AirbrakeResponse>(responseReader.ReadToEnd()); // Note: a success response means that the data has been received and accepted for processing. // Use the url or id in the response to query the status of an error. This will tell you if the error has been processed, // or if it has been rejected for reasons including invalid JSON and rate limiting. // If the request body size exceeds 64KB, the API will reject the notice and return a 413 Request Entity Too Large status. // TODO: Investigate response in case when request body size exceeds 64KB. airbrakeResponse.Status = httpResponse.StatusCode == HttpStatusCode.Created ? RequestStatus.Success : RequestStatus.RequestError; tcs.SetResult(airbrakeResponse); } } finally { var disposableResponse = httpResponse as IDisposable; if (disposableResponse != null) { disposableResponse.Dispose(); } } } }); } }); } catch (Exception ex) { tcs.SetException(ex); return(tcs.Task); } return(tcs.Task); }
/// <summary> /// Notifies Airbrake on error in your app using asynchronous call. /// </summary> #if NET35 public void NotifyAsync(Exception exception, IHttpContext context = null) { if (string.IsNullOrEmpty(config.ProjectId)) { throw new Exception("Project Id is required"); } if (string.IsNullOrEmpty(config.ProjectKey)) { throw new Exception("Project Key is required"); } try { if (Utils.IsIgnoredEnvironment(config.Environment, config.IgnoreEnvironments)) { var response = new AirbrakeResponse { Status = RequestStatus.Ignored }; OnNotifyCompleted(new NotifyCompletedEventArgs(response, null, false, null)); return; } var noticeBuilder = new NoticeBuilder(); noticeBuilder.SetErrorEntries(exception); noticeBuilder.SetConfigurationContext(config); if (context != null) { noticeBuilder.SetHttpContext(context, config); } noticeBuilder.SetEnvironmentContext(Dns.GetHostName(), Environment.OSVersion.VersionString, "C#/NET35"); var notice = noticeBuilder.ToNotice(); if (filters.Count > 0) { notice = Utils.ApplyFilters(notice, filters); } if (notice == null) { var response = new AirbrakeResponse { Status = RequestStatus.Ignored }; OnNotifyCompleted(new NotifyCompletedEventArgs(response, null, false, null)); return; } var request = httpRequestHandler.Get(); request.ContentType = "application/json"; request.Accept = "application/json"; request.Method = "POST"; request.BeginGetRequestStream(requestStreamResult => { try { var req = (IHttpRequest)requestStreamResult.AsyncState; var requestStream = req.EndGetRequestStream(requestStreamResult); using (var requestWriter = new StreamWriter(requestStream)) requestWriter.Write(NoticeBuilder.ToJsonString(notice)); req.BeginGetResponse(respRes => { IHttpResponse httpResponse = null; try { var req2 = (IHttpRequest)respRes.AsyncState; httpResponse = req2.EndGetResponse(respRes); using (var respStream = httpResponse.GetResponseStream()) using (var responseReader = new StreamReader(respStream)) { var airbrakeResponse = JsonConvert.DeserializeObject <AirbrakeResponse>(responseReader.ReadToEnd()); airbrakeResponse.Status = httpResponse.StatusCode == HttpStatusCode.Created ? RequestStatus.Success : RequestStatus.RequestError; OnNotifyCompleted(new NotifyCompletedEventArgs(airbrakeResponse, null, false, null)); } } catch (Exception respException) { OnNotifyCompleted(new NotifyCompletedEventArgs(null, respException, false, null)); } finally { var disposableResponse = httpResponse as IDisposable; if (disposableResponse != null) { disposableResponse.Dispose(); } } }, req); } catch (Exception reqException) { OnNotifyCompleted(new NotifyCompletedEventArgs(null, reqException, false, null)); } }, request); } catch (Exception ex) { OnNotifyCompleted(new NotifyCompletedEventArgs(null, ex, false, null)); } }
/// <summary> /// Notifies Airbrake on the error using the <see cref="Notice"/> object. /// </summary> /// <param name="notice">The notice describing the error.</param> /// <returns>Task which represents an asynchronous operation to Airbrake.</returns> public Task <AirbrakeResponse> NotifyAsync(Notice notice) { var log = InternalLogger.CreateInstance(); if (string.IsNullOrEmpty(config.ProjectId)) { log.Trace("Project Id is required"); throw new Exception("Project Id is required"); } if (string.IsNullOrEmpty(config.ProjectKey)) { log.Trace("Project Key is required"); throw new Exception("Project Key is required"); } // Task-based Asynchronous Pattern (https://msdn.microsoft.com/en-us/library/hh873177.aspx) var tcs = new TaskCompletionSource <AirbrakeResponse>(); try { if (notice == null) { var response = new AirbrakeResponse { Status = RequestStatus.Ignored }; tcs.SetResult(response); log.Trace("Notice is empty"); return(tcs.Task); } if (filters.Count > 0) { log.Trace("Applying filters"); notice = Utils.ApplyFilters(notice, filters); } if (notice == null) { var response = new AirbrakeResponse { Status = RequestStatus.Ignored }; tcs.SetResult(response); log.Trace("Ignoring notice because of filters"); return(tcs.Task); } if (Utils.IsIgnoredEnvironment(config.Environment, config.IgnoreEnvironments)) { var response = new AirbrakeResponse { Status = RequestStatus.Ignored }; tcs.SetResult(response); log.Trace("Ignoring notice for environment: {0}", config.Environment); return(tcs.Task); } #if !NETSTANDARD1_4 ServicePointManager.SecurityProtocol |= SecurityProtocolType.Tls12; #endif var request = httpRequestHandler.Get(); request.ContentType = "application/json"; request.Accept = "application/json"; request.Method = "POST"; if (!string.IsNullOrEmpty(config.ProxyUri)) { request.Proxy = Utils.ConfigureProxy( config.ProxyUri, config.ProxyUsername, config.ProxyPassword); } request.GetRequestStreamAsync().ContinueWith(requestStreamTask => { if (requestStreamTask.IsFaulted) { if (requestStreamTask.Exception != null) { var exceptions = requestStreamTask.Exception.InnerExceptions; tcs.SetException(exceptions); log.Trace("Exception occurred in request stream: {0}", exceptions.First().Message); } log.Trace("Request stream is faulted"); } else if (requestStreamTask.IsCanceled) { tcs.SetCanceled(); log.Trace("Request stream is canceled"); } else { using (var requestStream = requestStreamTask.Result) using (var requestWriter = new StreamWriter(requestStream)) { log.Trace("Writing to request stream"); requestWriter.Write(notice.ToJsonString()); } request.GetResponseAsync().ContinueWith(responseTask => { if (responseTask.IsFaulted) { if (responseTask.Exception != null) { var exceptions = responseTask.Exception.InnerExceptions; tcs.SetException(exceptions); log.Trace("Exception occurred in response task: {0}", exceptions.First().Message); } log.Trace("Response task is faulted"); } else if (responseTask.IsCanceled) { tcs.SetCanceled(); log.Trace("Response task is canceled"); } else { IHttpResponse httpResponse = null; try { httpResponse = responseTask.Result; using (var responseStream = httpResponse.GetResponseStream()) using (var responseReader = new StreamReader(responseStream)) { var serializerSettings = new DataContractJsonSerializerSettings { UseSimpleDictionaryFormat = true }; var serializer = new DataContractJsonSerializer(typeof(AirbrakeResponse), serializerSettings); AirbrakeResponse airbrakeResponse; using (var memoryStream = new MemoryStream(Encoding.UTF8.GetBytes(responseReader.ReadToEnd()))) { memoryStream.Position = 0; airbrakeResponse = (AirbrakeResponse)serializer.ReadObject(memoryStream); } // Note: a success response means that the data has been received and accepted for processing. // Use the URL or id from the response to query the status of an error. This will tell you if the error has been processed, // or if it has been rejected for reasons including invalid JSON and rate limiting. airbrakeResponse.Status = httpResponse.StatusCode == HttpStatusCode.Created ? RequestStatus.Success : RequestStatus.RequestError; tcs.SetResult(airbrakeResponse); log.Trace("Notice was registered: {0}", airbrakeResponse.Url); logResponse?.Invoke(airbrakeResponse); } } finally { var disposableResponse = httpResponse as IDisposable; disposableResponse?.Dispose(); } } }); } }); } catch (Exception ex) { tcs.SetException(ex); log.Trace("Exception occurred when sending notice: {0}", ex.Message); return(tcs.Task); } return(tcs.Task); }