-
Notifications
You must be signed in to change notification settings - Fork 73
/
recipe_log_forwarder.go
130 lines (110 loc) · 3.53 KB
/
recipe_log_forwarder.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
package execution
import (
"bufio"
"fmt"
"io"
"os"
"strconv"
"strings"
"time"
"github.com/fatih/color"
log "github.com/sirupsen/logrus"
"golang.org/x/net/context"
nrConfig "github.com/newrelic/newrelic-client-go/v2/pkg/config"
nrLogs "github.com/newrelic/newrelic-client-go/v2/pkg/logs"
"github.com/newrelic/newrelic-client-go/v2/pkg/region"
)
type LogForwarder interface {
PromptUserToSendLogs(reader io.Reader) bool
SendLogsToNewRelic(recipeName string, data []string)
HasUserOptedIn() bool
SetUserOptedIn(val bool)
}
type LogEntry struct {
Attributes map[string]interface{} `json:"attributes"`
LogType string `json:"logType"`
Message string `json:"message"`
}
type RecipeLogForwarder struct {
LogEntries []LogEntry
optIn bool
}
func NewRecipeLogForwarder() *RecipeLogForwarder {
return &RecipeLogForwarder{
LogEntries: []LogEntry{},
optIn: false,
}
}
func (lf *RecipeLogForwarder) PromptUserToSendLogs(reader io.Reader) bool {
fmt.Printf("\n%s Something went wrong during the installation — let’s look at the docs and try again. Would you like to send us the logs to help us understand what happened? [Y/n] ", color.YellowString("\u0021"))
scanner := bufio.NewScanner(reader)
for scanner.Scan() {
input := strings.TrimSuffix(scanner.Text(), "\n")
if strings.ToUpper(input) == "Y" || len(strings.TrimSpace(input)) == 0 {
return true
}
return false
}
if scanner.Err() != nil {
log.Debugf("An error occurred while reading input: %e", scanner.Err())
}
return false
}
func (lf *RecipeLogForwarder) HasUserOptedIn() bool {
return lf.optIn
}
func (lf *RecipeLogForwarder) SetUserOptedIn(val bool) {
lf.optIn = val
}
func (lf *RecipeLogForwarder) SendLogsToNewRelic(recipeName string, data []string) {
lf.buildLogEntryBatch(recipeName, data)
// building log api client
config, err := createLogClientConfig()
if nil != err {
log.Debugf("Could not configure New Relic LogsApi client: %e", err)
return
}
logClient := nrLogs.New(config)
// fetch accountId & configure client for batch mode
accountID, err := strconv.Atoi(os.Getenv("NEW_RELIC_ACCOUNT_ID"))
if nil != err {
log.Debugf("Could not determine account id for log destintation: %e", err)
return
}
if err := logClient.BatchMode(context.Background(), accountID); err != nil {
log.Fatal("error starting batch mode: ", err)
}
// enqueue log entries.
for _, logEntry := range lf.LogEntries {
if err := logClient.EnqueueLogEntry(context.Background(), logEntry); err != nil {
log.Fatal("error queuing log entry: ", err)
}
}
// Force flush/send; sleep seems necessary, otherwise logs don't appear to land in NR
time.Sleep(5 * time.Second)
if err := logClient.Flush(); err != nil {
log.Fatal("error flushing log queue: ", err)
}
}
func (lf *RecipeLogForwarder) buildLogEntryBatch(recipeName string, data []string) {
now := time.Now().UnixMilli()
for _, line := range data {
now++ //using timestamp to retain log sequence
lf.LogEntries = append(lf.LogEntries, LogEntry{map[string]interface{}{"nr-install-recipe": recipeName, "timestamp": now}, "cli-output", line})
}
}
func createLogClientConfig() (nrConfig.Config, error) {
cfg := nrConfig.Config{
LicenseKey: os.Getenv("NEW_RELIC_LICENSE_KEY"),
LogLevel: "info",
Compression: nrConfig.Compression.None,
}
regName, _ := region.Parse(os.Getenv("NEW_RELIC_REGION"))
reg, _ := region.Get(regName)
err := cfg.SetRegion(reg)
if nil != err {
log.Debugf("Could not set region on LogsApi client: %e", err)
return cfg, err
}
return cfg, nil
}