custom-script-extension-linux/main/telemetry.go

139 строки
3.0 KiB
Go

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,
},
},
}
}