public void AcceptDistributedTraceHeaders <T>(T carrier, Func <T, string, IEnumerable <string> > getter, int transportType) { try { using (new IgnoreWork()) { _apiSupportabilityMetricCounters.Record(ApiMethod.AcceptDistributedTraceHeaders); _transaction.AcceptDistributedTraceHeaders(carrier, getter, GetTransportTypeValue(transportType)); } } catch (Exception ex) { try { Log.ErrorFormat("Error in AcceptDistributedTraceHeaders<T>(T, Func<T, string, IEnumerable<string>>, TransportType): {0}", ex); } catch (Exception) { //Swallow the error } } }
public AfterWrappedMethodDelegate BeforeWrappedMethod(InstrumentedMethodCall instrumentedMethodCall, IAgent agent, ITransaction transaction) { var transactionAlreadyExists = transaction.IsValid; var methodInfo = TryGetMethodInfo(instrumentedMethodCall); if (methodInfo == null) { throw new NullReferenceException("methodInfo"); } var instrumentedMethodName = instrumentedMethodCall.MethodCall.Method.MethodName; var parameters = GetParameters(instrumentedMethodCall.MethodCall, methodInfo, instrumentedMethodCall.MethodCall.MethodArguments, agent); ReportSupportabilityMetric_InvocationMethod(agent, instrumentedMethodName); var isTAP = instrumentedMethodCall.InstrumentedMethodInfo.Method.Type.Name == TAPTypeNameShort; var shouldTryProcessInboundCatOrDT = _methodNamesStart.Contains(instrumentedMethodName); var shouldTryEndTransaction = _methodNamesEndTrx.Contains(instrumentedMethodName); var uri = OperationContext.Current?.IncomingMessageHeaders?.To; var transactionName = GetTransactionName(agent, uri, methodInfo); // In all cases, we should record this work in a transaction. // either create it or use the one that is already there // For InvokeEnd, we expect a transaction to be there, but create it // just in case. if (!transactionAlreadyExists) { transaction = agent.CreateTransaction( isWeb: true, category: EnumNameCache <WebTransactionType> .GetName(WebTransactionType.WCF), transactionDisplayName: "Windows Communication Foundation", doNotTrackAsUnitOfWork: false); transaction.GetExperimentalApi().SetWrapperToken(_wrapperToken); } var requestPath = uri?.AbsolutePath; if (!string.IsNullOrEmpty(requestPath)) { transaction.SetUri(requestPath); } // For InvokeBegin, Invoke, or InvokeAsync, Set the transaction name and process // CAT or DT request information. if (shouldTryProcessInboundCatOrDT) { transaction.SetWebTransactionName(WebTransactionType.WCF, transactionName, TransactionNamePriority.FrameworkHigh); transaction.SetRequestParameters(parameters); if (!transactionAlreadyExists) { var transportType = TransportType.Other; var msgProperties = OperationContext.Current?.IncomingMessageProperties; if (msgProperties != null && msgProperties.TryGetValue(HttpRequestMessageProperty.Name, out var httpRequestMessageObject)) { if (httpRequestMessageObject is HttpRequestMessageProperty) { transportType = TransportType.HTTP; } } transaction.AcceptDistributedTraceHeaders(OperationContext.Current, ExtractHeaderValue, transportType); } } // Don't create a segment to cover the EndInvoke on TAP Invocation // but we need to instrument the EndInvoke so that we can close the // transaction and send the CAT Response. The continuation that // is used for TAP will not reliably have access to the OperationContext ISegment segment = null; if (!isTAP || _methodNamesStart.Contains(instrumentedMethodName)) { segment = transaction.StartTransactionSegment(instrumentedMethodCall.MethodCall, transactionName); if (isTAP) { segment.AlwaysDeductChildDuration = true; } } Guid?wrapperExecutionID = null; void WriteLogMessage(string message) { if (!agent.Logger.IsEnabledFor(Agent.Extensions.Logging.Level.Finest)) { return; } if (wrapperExecutionID == null) { wrapperExecutionID = Guid.NewGuid(); } transaction.LogFinest($"Execution {wrapperExecutionID} - {instrumentedMethodName}: {message}"); } var handledException = false; var isTAPContinuation = false; // This continuation method is meant for TAP Async only (InvokeAsync) // We don't end the transaction at this point because we dont // have access to the OperationContext. We rely on the (InvokeEnd) // to handle this part. void HandleContinuation(System.Threading.Tasks.Task t) { WriteLogMessage("Continuation"); if (t.IsFaulted) { WriteLogMessage("Continuation - Notice Exception"); transaction.NoticeError(t.Exception); } if (segment != null) { WriteLogMessage("Continuation - End Segment"); segment.End(); } } return(Delegates.GetDelegateFor( // This could occur on the Invoke, InvokeBegin, InvokeEnd onFailure: (Exception ex) => { WriteLogMessage("OnFailure"); transaction.NoticeError(ex); handledException = true; }, // This will get called on both Begin/End and TAP (InvokeAsync) onSuccess: (System.Threading.Tasks.Task result) => { // If it is TAP, need to wait until the async work is done. // attach continuation to determine if exception has occurred and // to end the segment. For Begin/End, there is nothing to do // in the continuation. if (isTAP) { WriteLogMessage("OnSuccess - Schedule Continuation"); isTAPContinuation = true; result.ContinueWith(HandleContinuation); } }, onComplete: () => { // If this is the TAP InvokeAsync, there is nothing to do here // The continuation has been set up and it will determine if there // are any problems and to end the segment. if (isTAPContinuation) { WriteLogMessage("OnComplete - NoOp wait for continuation"); return; } // In all cases, there is a segment, we want to end it. // The only case where we wouldn't have a segment would be // in the InvokeEnd for TAP if (segment != null) { WriteLogMessage("OnComplete - End Segment"); segment.End(); } // If an exception has occurred or if this is Invoke or InvokeEnd, // the transaction should be closed and CAT Response prepared. if (handledException || shouldTryEndTransaction) { var wcfStartedTransaction = transaction.GetExperimentalApi().GetWrapperToken() == _wrapperToken; if (wcfStartedTransaction) { WriteLogMessage("OnComplete - End transaction"); transaction.End(); ProcessResponse(transaction, OperationContext.Current); } } })); }