/
telemetry.go
138 lines (115 loc) · 2.96 KB
/
telemetry.go
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
package main
import (
"encoding/json"
"fmt"
"io"
"os"
"path"
"time"
"github.com/pkg/errors"
)
const (
telemetryEventsPath = "/var/lib/waagent/events"
)
type telemetryParameterString struct {
Name string `json:"name"`
Value string `json:"value"`
}
type telemetryParameterLong struct {
Name string `json:"name"`
Value int64 `json:"value"`
}
type telemetryParameterBool struct {
Name string `json:"name"`
Value bool `json:"value"`
}
type telemetryEvent struct {
EventId int `json:"eventId"`
ProviderId string `json:"providerId"`
Parameters []interface{} `json:"parameters"`
}
type telemetryEventWriter struct {
fh *os.File
}
func (w *telemetryEventWriter) Write(bs []byte) (n int, err error) {
fn := getTelemetryFileName()
temp := fn + ".tmp"
fh, err := os.OpenFile(temp, os.O_WRONLY|os.O_TRUNC|os.O_CREATE, 0400)
if err != nil {
return 0, errors.Wrap(err, "failed to open telemetry file")
}
w.fh = fh
n, err = w.fh.Write(bs)
err = os.Rename(temp, fn)
return
}
func (w *telemetryEventWriter) Close() (err error) {
if w.fh != nil {
err = w.fh.Close()
w.fh = nil
}
return
}
type telemetryEventSender struct {
writer io.WriteCloser
}
func newTelemetryEventSender() *telemetryEventSender {
return newTelemetryEventSenderWithWriteCloser(&telemetryEventWriter{})
}
func sendTelemetry(sender *telemetryEventSender, name, version string) func(operation, message string, isSuccess bool, duration time.Duration) error {
return func(operation, message string, isSuccess bool, duration time.Duration) error {
e := newTelemetryEvent(name, version, operation, message, isSuccess, duration)
return sender.send(e)
}
}
func newTelemetryEventSenderWithWriteCloser(writer io.WriteCloser) *telemetryEventSender {
return &telemetryEventSender{writer: writer}
}
func (w *telemetryEventSender) send(e telemetryEvent) error {
defer w.writer.Close()
bs, err := json.Marshal(e)
if err != nil {
return errors.Wrap(err, "failed to marhsal telemetry event")
}
_, err = w.writer.Write(bs)
if err != nil {
return errors.Wrap(err, "failed to write telemetry event")
}
return nil
}
func getTelemetryFileName() string {
fn := fmt.Sprintf("%d.tld", time.Now().UnixNano())
return path.Join(telemetryEventsPath, fn)
}
func newTelemetryEvent(name, version, operation, message string, isSuccess bool, duration time.Duration) telemetryEvent {
return telemetryEvent{
EventId: 1,
ProviderId: "69B669B9-4AF8-4C50-BDC4-6006FA76E975",
Parameters: []interface{}{
telemetryParameterString{
Name: "Name",
Value: name,
},
telemetryParameterString{
Name: "Version",
Value: version,
},
telemetryParameterString{
Name: "Operation",
Value: operation,
},
telemetryParameterBool{
Name: "OperationSuccess",
Value: isSuccess,
},
telemetryParameterString{
Name: "Message",
Value: message,
},
telemetryParameterLong{
Name: "Duration",
Value: duration.Nanoseconds() / 1e6,
},
},
}
}