aboutsummaryrefslogtreecommitdiffstats
path: root/vendor/github.com/maruel/panicparse/stack/ui.go
blob: b125fc9406879373ef268f52dfea20b1d8712f32 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
// Copyright 2016 Marc-Antoine Ruel. All rights reserved.
// Use of this source code is governed under the Apache License, Version 2.0
// that can be found in the LICENSE file.

package stack

import (
    "fmt"
    "strings"
)

// Palette defines the color used.
//
// An empty object Palette{} can be used to disable coloring.
type Palette struct {
    EOLReset string

    // Routine header.
    RoutineFirst string // The first routine printed.
    Routine      string // Following routines.
    CreatedBy    string

    // Call line.
    Package                string
    SourceFile             string
    FunctionStdLib         string
    FunctionStdLibExported string
    FunctionMain           string
    FunctionOther          string
    FunctionOtherExported  string
    Arguments              string
}

// CalcLengths returns the maximum length of the source lines and package names.
func CalcLengths(buckets Buckets, fullPath bool) (int, int) {
    srcLen := 0
    pkgLen := 0
    for _, bucket := range buckets {
        for _, line := range bucket.Signature.Stack.Calls {
            l := 0
            if fullPath {
                l = len(line.FullSourceLine())
            } else {
                l = len(line.SourceLine())
            }
            if l > srcLen {
                srcLen = l
            }
            l = len(line.Func.PkgName())
            if l > pkgLen {
                pkgLen = l
            }
        }
    }
    return srcLen, pkgLen
}

// functionColor returns the color to be used for the function name based on
// the type of package the function is in.
func (p *Palette) functionColor(line *Call) string {
    if line.IsStdlib() {
        if line.Func.IsExported() {
            return p.FunctionStdLibExported
        }
        return p.FunctionStdLib
    } else if line.IsPkgMain() {
        return p.FunctionMain
    } else if line.Func.IsExported() {
        return p.FunctionOtherExported
    }
    return p.FunctionOther
}

// routineColor returns the color for the header of the goroutines bucket.
func (p *Palette) routineColor(bucket *Bucket, multipleBuckets bool) string {
    if bucket.First() && multipleBuckets {
        return p.RoutineFirst
    }
    return p.Routine
}

// BucketHeader prints the header of a goroutine signature.
func (p *Palette) BucketHeader(bucket *Bucket, fullPath, multipleBuckets bool) string {
    extra := ""
    if bucket.SleepMax != 0 {
        if bucket.SleepMin != bucket.SleepMax {
            extra += fmt.Sprintf(" [%d~%d minutes]", bucket.SleepMin, bucket.SleepMax)
        } else {
            extra += fmt.Sprintf(" [%d minutes]", bucket.SleepMax)
        }
    }
    if bucket.Locked {
        extra += " [locked]"
    }
    created := bucket.CreatedBy.Func.PkgDotName()
    if created != "" {
        created += " @ "
        if fullPath {
            created += bucket.CreatedBy.FullSourceLine()
        } else {
            created += bucket.CreatedBy.SourceLine()
        }
        extra += p.CreatedBy + " [Created by " + created + "]"
    }
    return fmt.Sprintf(
        "%s%d: %s%s%s\n",
        p.routineColor(bucket, multipleBuckets), len(bucket.Routines),
        bucket.State, extra,
        p.EOLReset)
}

// callLine prints one stack line.
func (p *Palette) callLine(line *Call, srcLen, pkgLen int, fullPath bool) string {
    src := ""
    if fullPath {
        src = line.FullSourceLine()
    } else {
        src = line.SourceLine()
    }
    return fmt.Sprintf(
        "    %s%-*s %s%-*s %s%s%s(%s)%s",
        p.Package, pkgLen, line.Func.PkgName(),
        p.SourceFile, srcLen, src,
        p.functionColor(line), line.Func.Name(),
        p.Arguments, line.Args,
        p.EOLReset)
}

// StackLines prints one complete stack trace, without the header.
func (p *Palette) StackLines(signature *Signature, srcLen, pkgLen int, fullPath bool) string {
    out := make([]string, len(signature.Stack.Calls))
    for i := range signature.Stack.Calls {
        out[i] = p.callLine(&signature.Stack.Calls[i], srcLen, pkgLen, fullPath)
    }
    if signature.Stack.Elided {
        out = append(out, "    (...)")
    }
    return strings.Join(out, "\n") + "\n"
}