internal static void AssertValid(this CapturedStackFrame thisObj)
        {
            thisObj.Should().NotBeNull();

            thisObj.FileName.Should().NotBeNullOrEmpty();
            thisObj.LineNo.Should().BeGreaterOrEqualTo(0);
            thisObj.Module?.Should().NotBeEmpty();
            thisObj.Function?.Should().NotBeEmpty();
        }
Пример #2
0
        private static void FullFwAssertValid(CapturedStackFrame capturedStackFrame)
        {
            capturedStackFrame.Should().NotBeNull();

            capturedStackFrame.Function.NonEmptyAssertValid();
        }
Пример #3
0
        /// <summary>
        /// Turns a System.Diagnostic.StackFrame[] into a <see cref="CapturedStackFrame" /> list which can be reported to the APM
        /// Server
        /// </summary>
        /// <param name="frames">The stack frames to rewrite into APM stack traces</param>
        /// <param name="logger">The logger to emit exceptions on should one occur</param>
        /// <param name="apmServerInfo">The ServerInfo instance to query the server version</param>
        /// <param name="dbgCapturingFor">Just for logging.</param>
        /// <param name="configurationReader">
        /// Config reader - this controls the collection of stack traces (e.g. limit on frames,
        /// etc)
        /// </param>
        /// <returns>A prepared List that can be passed to the APM server</returns>
        internal static List <CapturedStackFrame> GenerateApmStackTrace(StackFrame[] frames, IApmLogger logger,
                                                                        IConfigurationReader configurationReader, IApmServerInfo apmServerInfo, string dbgCapturingFor
                                                                        )
        {
            var stackTraceLimit = configurationReader.StackTraceLimit;

            if (stackTraceLimit == 0)
            {
                return(null);
            }

            if (stackTraceLimit > 0)
            {
                // new StackTrace(skipFrames: n) skips frames from the top of the stack (currently executing method is top)
                // the StackTraceLimit feature takes the top n frames, so unfortunately we currently capture the whole stack trace and just take
                // the top `configurationReader.StackTraceLimit` frames. - This could be optimized.
                frames = frames.Take(stackTraceLimit).ToArray();
            }

            var retVal = new List <CapturedStackFrame>(frames.Length);

            logger.Trace()?.Log("transform stack frames");

            try
            {
                foreach (var frame in frames)
                {
                    var className = frame?.GetMethod()
                                    ?.DeclaringType?.FullName;             //see: https://github.com/elastic/apm-agent-dotnet/pull/240#discussion_r289619196

                    var functionName = GetRealMethodName(frame?.GetMethod());
                    var fileName     = frame?.GetFileName();

                    logger.Trace()?.Log("{MethodName}, {lineNo}", functionName, frame?.GetFileLineNumber());

                    var capturedStackFrame = new CapturedStackFrame
                    {
                        Function = functionName ?? "N/A",
                        Module   = frame?.GetMethod()?.ReflectedType?.Assembly.FullName,
                        LineNo   = frame?.GetFileLineNumber() ?? 0,
                        AbsPath  = frame?.GetFileName()                        // optional property
                    };

                    if (apmServerInfo?.Version < V710)
                    {
                        // In pre 7.10, Kibana shows stack traces in format: `[FileName] in [MethodName]` and there is no way to show ClassName.
                        // For .NET that format is less useful especially because in some cases we only have a `.dll` file as filename.
                        // Therefore as a workaround we send the real classname in the file name field and
                        // we don't send anything in the ClassName field, since that's not used.
                        // If versions 7.09 is out of support, this code can be removed.
                        capturedStackFrame.FileName = string.IsNullOrWhiteSpace(className) ? "N/A" : className;
                    }
                    else
                    {
                        // FileName is either the .cs file or the assembly location as fallback
                        capturedStackFrame.FileName =
                            string.IsNullOrWhiteSpace(fileName)
                                                                ? string.IsNullOrEmpty(frame?.GetMethod()?.GetType().Assembly.Location) ? "n/a" :
                            frame.GetMethod()?.GetType().Assembly.Location
                                                                : fileName;

                        capturedStackFrame.ClassName = string.IsNullOrWhiteSpace(className) ? "N/A" : className;
                    }

                    retVal.Add(capturedStackFrame);
                }
            }
            catch (Exception e)
            {
                logger?.Warning()?.LogException(e, "Failed capturing stacktrace for {ApmContext}", dbgCapturingFor);
            }

            return(retVal);
        }