public async void StartWork() { var httpClient = new HttpClient { BaseAddress = _serverUrlBase }; while (true) { var item = _payloads.Take(); try { var json = JsonConvert.SerializeObject(item, new JsonSerializerSettings { ContractResolver = new CamelCasePropertyNamesContractResolver() }); var content = new StringContent(json, Encoding.UTF8, "application/json"); HttpResponseMessage result = null; switch (item) { case Payload p: result = await httpClient.PostAsync(Consts.IntakeV1Transactions, content); break; case Error e: result = await httpClient.PostAsync(Consts.IntakeV1Errors, content); break; } var isSucc = result.IsSuccessStatusCode; var str = await result.Content.ReadAsStringAsync(); } catch (Exception e) { switch (item) { case Payload p: _logger.LogWarning($"Failed sending transaction {p.Transactions.FirstOrDefault()?.Name}"); _logger.LogDebug($"{e.GetType().Name}: {e.Message}"); break; case Error err: _logger.LogWarning($"Failed sending Error {err.Errors[0]?.Id}"); _logger.LogDebug($"{e.GetType().Name}: {e.Message}"); break; } } } }
/// <summary> /// Turns a System.Diagnostic.StackFrame[] into a <see cref="Stacktrace"/> list which can be reported to the APM Server /// </summary> /// <param name="capturingFor">Just for logging.</param> /// <returns>A prepared List that can be passed to the APM server</returns> public static List <Stacktrace> GenerateApmStackTrace(StackFrame[] frames, AbstractLogger logger, string capturingFor) { var retVal = new List <Stacktrace>(frames.Length); try { foreach (var item in frames) { var fileName = item?.GetMethod()?.DeclaringType?.Assembly?.GetName()?.Name; if (String.IsNullOrEmpty(fileName)) { continue; //since filename is required by the server, if we don't have it we skip the frame } retVal.Add(new Stacktrace { Function = item?.GetMethod()?.Name, Filename = fileName, Module = item?.GetMethod()?.ReflectedType?.Name }); } } catch (Exception e) { logger.LogWarning($"Failed capturing stacktrace for {capturingFor}"); logger.LogDebug($"{e.GetType().Name}: {e.Message}"); } return(retVal); }
/// <summary> /// Turns a System.Diagnostic.StackFrame[] into a <see cref="Stacktrace" /> list which can be reported to the APM Server /// </summary> /// <param name="capturingFor">Just for logging.</param> /// <returns>A prepared List that can be passed to the APM server</returns> internal static List <Stacktrace> GenerateApmStackTrace(StackFrame[] frames, AbstractLogger logger, string capturingFor) { var retVal = new List <Stacktrace>(frames.Length); try { retVal.AddRange(from item in frames let fileName = item?.GetMethod()?.DeclaringType?.Assembly?.GetName()?.Name where !string.IsNullOrEmpty(fileName) select new Stacktrace { Function = item?.GetMethod()?.Name, FileName = fileName, Module = item?.GetMethod()?.ReflectedType?.Name, LineNo = item?.GetFileLineNumber() ?? 0 }); } catch (Exception e) { logger.LogWarning($"Failed capturing stacktrace for {capturingFor}"); logger.LogDebug($"{e.GetType().Name}: {e.Message}"); } return(retVal); }
private void LogWithLevel(LogLevel logLevel) { Apm.Agent.Config.LogLevel = logLevel; logger.LogError("Error log"); logger.LogWarning("Warning log"); logger.LogInfo("Info log"); logger.LogDebug("Debug log"); }
public void OnNext(KeyValuePair <string, object> kv) { if (kv.Value == null || String.IsNullOrEmpty(kv.Key)) { return; } if (!(kv.Value.GetType().GetTypeInfo().GetDeclaredProperty("Request")?.GetValue(kv.Value) is HttpRequestMessage request)) { return; } if (IsRequestFiltered(request?.RequestUri)) { return; } switch (kv.Key) { case "System.Net.Http.Exception": var exception = kv.Value.GetType().GetTypeInfo().GetDeclaredProperty("Exception").GetValue(kv.Value) as Exception; var transaction = TransactionContainer.Transactions?.Value[0]; var error = new Error { Errors = new List <Error.Err> { new Error.Err { Culprit = "Failed outgoing HTTP request", Exception = new CapturedException { Message = exception.Message, Type = exception.GetType().FullName //Handled TODO: this exception can be handled later }, Transaction = new Error.Err.Trans { Id = transaction.Id }, Id = Guid.NewGuid(), Timestamp = DateTime.UtcNow.ToString("yyyy-MM-ddTHH:mm:ss.FFFZ") } }, Service = transaction.service }; if (!String.IsNullOrEmpty(exception.StackTrace)) { error.Errors[0].Exception.Stacktrace = StacktraceHelper.GenerateApmStackTrace(new System.Diagnostics.StackTrace(exception).GetFrames(), logger, "failed outgoing HTTP request"); } if (transaction.Context != null) { error.Errors[0].Context = transaction.Context; } Agent.PayloadSender.QueueError(error); break; case "System.Net.Http.HttpRequestOut.Start": //TODO: look for consts if (TransactionContainer.Transactions == null || TransactionContainer.Transactions.Value == null) { return; } var transactionStartTime = TransactionContainer.Transactions.Value[0].TimestampInDateTime; var utcNow = DateTime.UtcNow; var http = new Http { Url = request?.RequestUri?.ToString(), Method = request?.Method?.Method, }; var span = new Span { Start = (decimal)(utcNow - transactionStartTime).TotalMilliseconds, Name = $"{request?.Method} {request?.RequestUri?.Host?.ToString()}", Type = Consts.EXTERNAL, Subtype = Consts.HTTP, Context = new Span.ContextC { Http = http } }; if (processingRequests.TryAdd(request, span)) { var frames = new System.Diagnostics.StackTrace().GetFrames(); var stackFrames = StacktraceHelper.GenerateApmStackTrace(frames, logger, span.Name); span.Stacktrace = stackFrames; } break; case "System.Net.Http.HttpRequestOut.Stop": var response = kv.Value.GetType().GetTypeInfo().GetDeclaredProperty("Response").GetValue(kv.Value) as HttpResponseMessage; if (processingRequests.TryRemove(request, out Span mspan)) { //TODO: response can be null if for example the request Task is Faulted. //E.g. writing this from an airplane without internet, and requestTaskStatus is "Faulted" and response is null //How do we report this? There is no response code in that case. if (response != null) { mspan.Context.Http.Status_code = (int)response.StatusCode; } //TODO: there are better ways var endTime = (DateTime.UtcNow - TransactionContainer.Transactions.Value[0].TimestampInDateTime).TotalMilliseconds; mspan.Duration = endTime - (double)mspan.Start; TransactionContainer.Transactions?.Value[0]?.Spans?.Add(mspan); } else { logger.LogWarning($"Failed capturing request" + (!String.IsNullOrEmpty(request?.RequestUri?.AbsoluteUri) && !String.IsNullOrEmpty(request?.Method?.ToString()) ? $" '{request?.Method.ToString()} " : " ") + (String.IsNullOrEmpty(request?.RequestUri?.AbsoluteUri) ? "" : $"{request?.RequestUri.AbsoluteUri}' ") + "in System.Net.Http.HttpRequestOut.Stop. This Span will be skipped in case it wasn't captured before."); } break; } }
public void OnNext(KeyValuePair <string, object> kv) { if (kv.Value == null || String.IsNullOrEmpty(kv.Key)) { return; } if (!(kv.Value.GetType().GetTypeInfo().GetDeclaredProperty("Request")?.GetValue(kv.Value) is HttpRequestMessage request)) { return; } if (IsRequestFiltered(request?.RequestUri)) { return; } switch (kv.Key) { case "System.Net.Http.Exception": var exception = kv.Value.GetType().GetTypeInfo().GetDeclaredProperty("Exception").GetValue(kv.Value) as Exception; var transaction = TransactionContainer.Transactions?.Value; transaction.CaptureException(exception, "Failed outgoing HTTP request"); //TODO: we don't know if exception is handled, currently reports handled = false break; case "System.Net.Http.HttpRequestOut.Start": //TODO: look for consts if (TransactionContainer.Transactions == null || TransactionContainer.Transactions.Value == null) { return; } transaction = TransactionContainer.Transactions.Value; var span = transaction.StartSpan($"{request?.Method} {request?.RequestUri?.Host?.ToString()}", Span.TYPE_EXTERNAL, Span.SUBTYPE_HTTP); if (processingRequests.TryAdd(request, span)) { span.Context = new Span.ContextC { Http = new Http { Url = request?.RequestUri?.ToString(), Method = request?.Method?.Method, } }; var frames = new System.Diagnostics.StackTrace().GetFrames(); var stackFrames = StacktraceHelper.GenerateApmStackTrace(frames, logger, span.Name); span.Stacktrace = stackFrames; } break; case "System.Net.Http.HttpRequestOut.Stop": var response = kv.Value.GetType().GetTypeInfo().GetDeclaredProperty("Response").GetValue(kv.Value) as HttpResponseMessage; if (processingRequests.TryRemove(request, out ISpan mspan)) { //TODO: response can be null if for example the request Task is Faulted. //E.g. writing this from an airplane without internet, and requestTaskStatus is "Faulted" and response is null //How do we report this? There is no response code in that case. if (response != null) { mspan.Context.Http.Status_code = (int)response.StatusCode; } mspan.End(); } else { logger.LogWarning($"Failed capturing request" + (!String.IsNullOrEmpty(request?.RequestUri?.AbsoluteUri) && !String.IsNullOrEmpty(request?.Method?.ToString()) ? $" '{request?.Method.ToString()} " : " ") + (String.IsNullOrEmpty(request?.RequestUri?.AbsoluteUri) ? "" : $"{request?.RequestUri.AbsoluteUri}' ") + "in System.Net.Http.HttpRequestOut.Stop. This Span will be skipped in case it wasn't captured before."); } break; } }