1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package exporter
18
19 import (
20 "context"
21 "encoding/hex"
22 "fmt"
23 "log"
24 "os"
25 "sync"
26 "time"
27
28 "go.opencensus.io/metric/metricdata"
29 "go.opencensus.io/metric/metricexport"
30 "go.opencensus.io/trace"
31 )
32
33
34 type LogExporter struct {
35 reader *metricexport.Reader
36 ir *metricexport.IntervalReader
37 initReaderOnce sync.Once
38 o Options
39 tFile *os.File
40 mFile *os.File
41 tLogger *log.Logger
42 mLogger *log.Logger
43 }
44
45
46 type Options struct {
47
48
49 ReportingInterval time.Duration
50
51
52
53 MetricsLogFile string
54
55
56
57 TracesLogFile string
58 }
59
60 func getLogger(filepath string) (*log.Logger, *os.File, error) {
61 if filepath == "" {
62 return log.New(os.Stdout, "", 0), nil, nil
63 }
64 f, err := os.OpenFile(filepath, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0666)
65 if err != nil {
66 return nil, nil, err
67 }
68 return log.New(f, "", 0), f, nil
69 }
70
71
72 func NewLogExporter(options Options) (*LogExporter, error) {
73 e := &LogExporter{reader: metricexport.NewReader(),
74 o: options}
75 var err error
76 e.tLogger, e.tFile, err = getLogger(options.TracesLogFile)
77 if err != nil {
78 return nil, err
79 }
80 e.mLogger, e.mFile, err = getLogger(options.MetricsLogFile)
81 if err != nil {
82 return nil, err
83 }
84 return e, nil
85 }
86
87 func printMetricDescriptor(metric *metricdata.Metric) string {
88 d := metric.Descriptor
89 return fmt.Sprintf("name: %s, type: %s, unit: %s ",
90 d.Name, d.Type, d.Unit)
91 }
92
93 func printLabels(metric *metricdata.Metric, values []metricdata.LabelValue) string {
94 d := metric.Descriptor
95 kv := []string{}
96 for i, k := range d.LabelKeys {
97 kv = append(kv, fmt.Sprintf("%s=%v", k, values[i]))
98 }
99 return fmt.Sprintf("%v", kv)
100 }
101
102 func printPoint(point metricdata.Point) string {
103 switch v := point.Value.(type) {
104 case *metricdata.Distribution:
105 dv := v
106 return fmt.Sprintf("count=%v sum=%v sum_sq_dev=%v, buckets=%v", dv.Count,
107 dv.Sum, dv.SumOfSquaredDeviation, dv.Buckets)
108 default:
109 return fmt.Sprintf("value=%v", point.Value)
110 }
111 }
112
113
114 func (e *LogExporter) Start() error {
115 trace.RegisterExporter(e)
116 e.initReaderOnce.Do(func() {
117 e.ir, _ = metricexport.NewIntervalReader(&metricexport.Reader{}, e)
118 })
119 e.ir.ReportingInterval = e.o.ReportingInterval
120 return e.ir.Start()
121 }
122
123
124 func (e *LogExporter) Stop() {
125 trace.UnregisterExporter(e)
126 e.ir.Stop()
127 }
128
129
130 func (e *LogExporter) Close() {
131 if e.tFile != nil {
132 e.tFile.Close()
133 e.tFile = nil
134 }
135 if e.mFile != nil {
136 e.mFile.Close()
137 e.mFile = nil
138 }
139 }
140
141
142 func (e *LogExporter) ExportMetrics(ctx context.Context, metrics []*metricdata.Metric) error {
143 for _, metric := range metrics {
144 for _, ts := range metric.TimeSeries {
145 for _, point := range ts.Points {
146 e.mLogger.Println("#----------------------------------------------")
147 e.mLogger.Println()
148 e.mLogger.Printf("Metric: %s\n Labels: %s\n Value : %s\n",
149 printMetricDescriptor(metric),
150 printLabels(metric, ts.LabelValues),
151 printPoint(point))
152 e.mLogger.Println()
153 }
154 }
155 }
156 return nil
157 }
158
159
160 func (e *LogExporter) ExportSpan(sd *trace.SpanData) {
161 var (
162 traceID = hex.EncodeToString(sd.SpanContext.TraceID[:])
163 spanID = hex.EncodeToString(sd.SpanContext.SpanID[:])
164 parentSpanID = hex.EncodeToString(sd.ParentSpanID[:])
165 )
166 e.tLogger.Println()
167 e.tLogger.Println("#----------------------------------------------")
168 e.tLogger.Println()
169 e.tLogger.Println("TraceID: ", traceID)
170 e.tLogger.Println("SpanID: ", spanID)
171 if !reZero.MatchString(parentSpanID) {
172 e.tLogger.Println("ParentSpanID:", parentSpanID)
173 }
174
175 e.tLogger.Println()
176 e.tLogger.Printf("Span: %v\n", sd.Name)
177 e.tLogger.Printf("Status: %v [%v]\n", sd.Status.Message, sd.Status.Code)
178 e.tLogger.Printf("Elapsed: %v\n", sd.EndTime.Sub(sd.StartTime).Round(time.Millisecond))
179
180 spanKinds := map[int]string{
181 1: "Server",
182 2: "Client",
183 }
184 if spanKind, ok := spanKinds[sd.SpanKind]; ok {
185 e.tLogger.Printf("SpanKind: %s\n", spanKind)
186 }
187
188 if len(sd.Annotations) > 0 {
189 e.tLogger.Println()
190 e.tLogger.Println("Annotations:")
191 for _, item := range sd.Annotations {
192 e.tLogger.Print(indent, item.Message)
193 for k, v := range item.Attributes {
194 e.tLogger.Printf(" %v=%v", k, v)
195 }
196 e.tLogger.Println()
197 }
198 }
199
200 if len(sd.Attributes) > 0 {
201 e.tLogger.Println()
202 e.tLogger.Println("Attributes:")
203 for k, v := range sd.Attributes {
204 e.tLogger.Printf("%v- %v=%v\n", indent, k, v)
205 }
206 }
207
208 if len(sd.MessageEvents) > 0 {
209 eventTypes := map[trace.MessageEventType]string{
210 trace.MessageEventTypeSent: "Sent",
211 trace.MessageEventTypeRecv: "Received",
212 }
213 e.tLogger.Println()
214 e.tLogger.Println("MessageEvents:")
215 for _, item := range sd.MessageEvents {
216 if eventType, ok := eventTypes[item.EventType]; ok {
217 e.tLogger.Print(eventType)
218 }
219 e.tLogger.Printf("UncompressedByteSize: %v", item.UncompressedByteSize)
220 e.tLogger.Printf("CompressedByteSize: %v", item.CompressedByteSize)
221 e.tLogger.Println()
222 }
223 }
224 }
225
View as plain text