public static string ResolveTracerFactoryNameForAttributeInstrumentation(uint tracerArguments, bool isAsync, string tracerFactoryName) { if (TracerArgument.IsFlagSet(tracerArguments, TracerFlags.AttributeInstrumentation)) { if (TracerArgument.IsFlagSet(tracerArguments, TracerFlags.WebTransaction) || TracerArgument.IsFlagSet(tracerArguments, TracerFlags.OtherTransaction)) { return(isAsync ? "NewRelic.Providers.Wrapper.CustomInstrumentationAsync.OtherTransactionWrapperAsync" : "NewRelic.Providers.Wrapper.CustomInstrumentation.OtherTransactionWrapper"); } } return(tracerFactoryName); }
public AfterWrappedMethodDelegate BeforeWrappedMethod(Type type, string methodName, string argumentSignature, object invocationTarget, object[] methodArguments, string tracerFactoryName, string metricName, uint tracerArguments, ulong functionId) { InstrumentedMethodInfo instrumentedMethodInfo = default(InstrumentedMethodInfo); TrackedWrapper trackedWrapper; if (_functionIdToWrapper.TryGetValue(functionId, out InstrumentedMethodInfoWrapper methodAndWrapper)) { instrumentedMethodInfo = methodAndWrapper.instrumentedMethodInfo; trackedWrapper = methodAndWrapper.wrapper; } else { var isAsync = TracerArgument.IsAsync(tracerArguments); tracerFactoryName = ResolveTracerFactoryNameForAttributeInstrumentation(tracerArguments, isAsync, tracerFactoryName); var method = new Method(type, methodName, argumentSignature, functionId.GetHashCode()); var transactionNamePriority = TracerArgument.GetTransactionNamingPriority(tracerArguments); instrumentedMethodInfo = new InstrumentedMethodInfo((long)functionId, method, tracerFactoryName, isAsync, metricName, transactionNamePriority, TracerArgument.IsFlagSet(tracerArguments, TracerFlags.WebTransaction)); trackedWrapper = _wrapperMap.Get(instrumentedMethodInfo); if (trackedWrapper == null) { Log.WarnFormat("WrapperMap.Get unexpectedly returned null for {0}.{1}({2}) in assembly [{3}] (requested wrapper name was {4}).", instrumentedMethodInfo.Method.Type.FullName, instrumentedMethodInfo.Method.MethodName, instrumentedMethodInfo.Method.ParameterTypeNames, instrumentedMethodInfo.Method.Type.Assembly.FullName, instrumentedMethodInfo.RequestedWrapperName); return(null); } _functionIdToWrapper[functionId] = new InstrumentedMethodInfoWrapper(instrumentedMethodInfo, trackedWrapper); GenerateLibraryVersionSupportabilityMetric(instrumentedMethodInfo); } var wrapper = trackedWrapper.Wrapper; var transaction = _agent.CurrentTransaction; if (Log.IsFinestEnabled) { transaction.LogFinest($"Attempting to execute {wrapper} found from InstrumentedMethodInfo: {instrumentedMethodInfo}"); } if (transaction.IsFinished) { if (Log.IsFinestEnabled) { if (wrapper.IsTransactionRequired) { transaction.LogFinest($"Transaction has already ended, skipping method {type.FullName}.{methodName}({argumentSignature})."); } else { transaction.LogFinest("Transaction has already ended, detaching from transaction storage context."); } } transaction.Detach(); transaction = _agent.CurrentTransaction; if (wrapper.IsTransactionRequired) { return(Delegates.NoOp); } } if (wrapper.IsTransactionRequired) { if (!transaction.IsValid) { if (Log.IsFinestEnabled) { transaction.LogFinest($"No transaction, skipping method {type.FullName}.{methodName}({argumentSignature})"); } return(Delegates.NoOp); } if (transaction.CurrentSegment.IsLeaf) { return(Delegates.NoOp); } } var methodCall = new MethodCall(instrumentedMethodInfo.Method, invocationTarget, methodArguments); var instrumentedMethodCall = new InstrumentedMethodCall(methodCall, instrumentedMethodInfo); // if the wrapper throws an exception when executing the pre-method code, make sure the wrapper isn't called again in the future try { using (_agentTimerService.StartNew("BeforeWrappedMethod", type.FullName, methodName)) { var afterWrappedMethod = wrapper.BeforeWrappedMethod(instrumentedMethodCall, _agent, transaction); return((result, exception) => { using (_agentTimerService.StartNew("AfterWrappedMethod", type.FullName, methodName)) { // if the wrapper throws an exception when executing the post-method code, make sure the wrapper isn't called again in the future try { afterWrappedMethod(result, exception); trackedWrapper.NoticeSuccess(); } catch (Exception) { HandleBeforeWrappedMethodException(functionId, trackedWrapper, instrumentedMethodCall, instrumentedMethodInfo); throw; } } }); } } catch { HandleBeforeWrappedMethodException(functionId, trackedWrapper, instrumentedMethodCall, instrumentedMethodInfo); throw; } }