Esempio n. 1
0
        protected override string CreateBody(ThreadSample threadSample)
        {
            // The stack follows the experimental GDI conventions described at
            // https://github.com/signalfx/gdi-specification/blob/29cbcbc969531d50ccfd0b6a4198bb8a89cedebb/specification/semantic_conventions.md#logrecord-message-fields

            var stackTraceBuilder = new StringBuilder();

            stackTraceBuilder.AppendFormat(
                CultureInfo.InvariantCulture,
                "\"{0}\" #{1} prio=0 os_prio=0 cpu=0 elapsed=0 tid=0x{2:x} nid=0x{3:x}\n",
                threadSample.Timestamp,
                threadSample.ThreadIndex,
                threadSample.ManagedId,
                threadSample.NativeId);

            // TODO Splunk: APMI-2565 here should go Thread state, equivalent of"    java.lang.Thread.State: TIMED_WAITING (sleeping)"
            stackTraceBuilder.Append("\n");

            foreach (var frame in threadSample.Frames)
            {
                stackTraceBuilder.Append("\tat ");
                stackTraceBuilder.Append(frame);
                stackTraceBuilder.Append('\n');
            }

            return(stackTraceBuilder.ToString());
        }
Esempio n. 2
0
        protected override string CreateBody(ThreadSample threadSample)
        {
            var pprof         = new Pprof();
            var sampleBuilder = new SampleBuilder();

            pprof.AddLabel(sampleBuilder, "source.event.time", threadSample.Timestamp.Milliseconds);

            if (threadSample.SpanId != 0 || threadSample.TraceIdHigh != 0 || threadSample.TraceIdLow != 0)
            {
                pprof.AddLabel(sampleBuilder, "span_id", threadSample.SpanId);
                pprof.AddLabel(sampleBuilder, "trace_id", TraceIdHelper.ToString(threadSample.TraceIdHigh, threadSample.TraceIdLow));
            }

            foreach (var methodName in threadSample.Frames)
            {
                sampleBuilder.AddLocationId(pprof.GetLocationId(methodName));
            }

            pprof.AddLabel(sampleBuilder, "thread.id", threadSample.ManagedId);
            pprof.AddLabel(sampleBuilder, "thread.name", threadSample.ThreadName);
            pprof.AddLabel(sampleBuilder, "thread.os.id", threadSample.NativeId);

            pprof.Profile.Samples.Add(sampleBuilder.Build());
            return(Serialize(pprof.Profile));
        }
 protected abstract string CreateBody(ThreadSample threadSample);
        /// <summary>
        /// Parses the thread sample batch.
        /// </summary>
        internal List <ThreadSample> Parse()
        {
            uint batchThreadIndex  = 0;
            var  samples           = new List <ThreadSample>();
            long sampleStartMillis = 0;

            while (_position < _length)
            {
                var operationCode = _buffer[_position];
                _position++;
                if (operationCode == OpCodes.StartBatch)
                {
                    var version = ReadInt();
                    if (version != 1)
                    {
                        return(null); // not able to parse
                    }

                    sampleStartMillis = ReadInt64();

                    if (IsLogLevelDebugEnabled)
                    {
                        var sampleStart = new DateTime(
                            (sampleStartMillis * TimeSpan.TicksPerMillisecond) + TimeConstants.UnixEpochInTicks).ToLocalTime();
                        Log.Debug(
                            "Parsing thread samples captured at {date} {time}",
                            sampleStart.ToLongDateString(),
                            sampleStart.ToLongTimeString());
                    }
                }
                else if (operationCode == OpCodes.StartSample)
                {
                    var managedId   = ReadInt();
                    var nativeId    = ReadInt();
                    var threadName  = ReadString();
                    var traceIdHigh = ReadInt64();
                    var traceIdLow  = ReadInt64();
                    var spanId      = ReadInt64();

                    var threadIndex = batchThreadIndex++;

                    var code = ReadShort();
                    if (code == 0)
                    {
                        // Empty stack, skip this sample.
                        continue;
                    }

                    var threadSample = new ThreadSample
                    {
                        Timestamp   = new ThreadSample.Time(sampleStartMillis),
                        TraceIdHigh = traceIdHigh,
                        TraceIdLow  = traceIdLow,
                        SpanId      = spanId,
                        ManagedId   = managedId,
                        NativeId    = nativeId,
                        ThreadName  = threadName,
                        ThreadIndex = threadIndex
                    };

                    while (code != 0)
                    {
                        string value;
                        if (code < 0)
                        {
                            value         = ReadString();
                            _codes[-code] = value;
                        }
                        else
                        {
                            value = _codes[code];
                        }

                        if (value != null)
                        {
                            // we are replacing Datadog.Trace namespace to avoid conflicts while upstream sync
                            var replacedValue = value.Replace("Datadog.Trace.", "SignalFx.Tracing.");
                            threadSample.Frames.Add(replacedValue);
                        }

                        code = ReadShort();
                    }

                    if (threadName == ThreadSampler.BackgroundThreadName)
                    {
                        // TODO Splunk: add configuration option to include the sampler thread. By default remove it.
                        continue;
                    }

                    samples.Add(threadSample);
                }
                else if (operationCode == OpCodes.EndBatch)
                {
                    // end batch, nothing here
                }
                else if (operationCode == OpCodes.BatchStats)
                {
                    var microsSuspended = ReadInt();
                    var numThreads      = ReadInt();
                    var totalFrames     = ReadInt();
                    var numCacheMisses  = ReadInt();

                    if (IsLogLevelDebugEnabled)
                    {
                        Log.Debug(
                            "CLR was suspended for {microsSuspended} microseconds to collect a thread sample batch: threads={numThreads} frames={totalFrames} misses={numCacheMisses}",
                            new object[] { microsSuspended, numThreads, totalFrames, numCacheMisses });
                    }
                }
                else
                {
                    _position = _length + 1;

                    if (IsLogLevelDebugEnabled)
                    {
                        Log.Debug("Not expected operation code while parsing thread stack trace: '{0}'. Operation will be ignored.", operationCode);
                    }
                }
            }

            return(samples);
        }