-
Notifications
You must be signed in to change notification settings - Fork 78
/
logger.go
146 lines (127 loc) · 3.69 KB
/
logger.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
139
140
141
142
143
144
145
146
// Package logger creates an osquery logging plugin.
//
// See https://osquery.readthedocs.io/en/latest/development/logger-plugins/ for more.
package logger
import (
"bytes"
"context"
"encoding/json"
"github.com/kolide/osquery-go/gen/osquery"
)
// LogFunc is the logger function used by an osquery Logger plugin.
//
// The LogFunc should log the provided result string. The LogType
// argument can be optionally used to log differently depending on the
// type of log received. The context argument can optionally be used
// for cancellation in long-running operations.
type LogFunc func(ctx context.Context, typ LogType, log string) error
// Plugin is an osquery logger plugin.
// The Plugin struct implements the OsqueryPlugin interface.
type Plugin struct {
name string
logFn LogFunc
}
// NewPlugin takes a value that implements LoggerPlugin and wraps it with
// the appropriate methods to satisfy the OsqueryPlugin interface. Use this to
// easily create plugins implementing osquery loggers.
func NewPlugin(name string, fn LogFunc) *Plugin {
return &Plugin{name: name, logFn: fn}
}
func (t *Plugin) Name() string {
return t.name
}
func (t *Plugin) RegistryName() string {
return "logger"
}
func (t *Plugin) Routes() osquery.ExtensionPluginResponse {
return []map[string]string{}
}
func (t *Plugin) Ping() osquery.ExtensionStatus {
return osquery.ExtensionStatus{Code: 0, Message: "OK"}
}
func (t *Plugin) Call(ctx context.Context, request osquery.ExtensionPluginRequest) osquery.ExtensionResponse {
var err error
if log, ok := request["string"]; ok {
err = t.logFn(ctx, LogTypeString, log)
} else if log, ok := request["snapshot"]; ok {
err = t.logFn(ctx, LogTypeSnapshot, log)
} else if log, ok := request["health"]; ok {
err = t.logFn(ctx, LogTypeHealth, log)
} else if log, ok := request["init"]; ok {
err = t.logFn(ctx, LogTypeInit, log)
} else if _, ok := request["status"]; ok {
statusJSON := []byte(request["log"])
if len(statusJSON) == 0 {
return osquery.ExtensionResponse{
Status: &osquery.ExtensionStatus{
Code: 1,
Message: "got empty status",
},
}
}
// Dirty hack because osquery gives us malformed JSON.
statusJSON = bytes.Replace(statusJSON, []byte(`"":`), []byte(``), -1)
statusJSON[0] = '['
statusJSON[len(statusJSON)-1] = ']'
var parsedStatuses []json.RawMessage
if err := json.Unmarshal(statusJSON, &parsedStatuses); err != nil {
return osquery.ExtensionResponse{
Status: &osquery.ExtensionStatus{
Code: 1,
Message: "error parsing status logs: " + err.Error(),
},
}
}
for _, s := range parsedStatuses {
err = t.logFn(ctx, LogTypeStatus, string(s))
}
} else {
return osquery.ExtensionResponse{
Status: &osquery.ExtensionStatus{
Code: 1,
Message: "unknown log request",
},
}
}
if err != nil {
return osquery.ExtensionResponse{
Status: &osquery.ExtensionStatus{
Code: 1,
Message: "error logging: " + err.Error(),
},
}
}
return osquery.ExtensionResponse{
Status: &osquery.ExtensionStatus{Code: 0, Message: "OK"},
Response: osquery.ExtensionPluginResponse{},
}
}
func (t *Plugin) Shutdown() {}
//LogType encodes the type of log osquery is outputting.
type LogType int
const (
LogTypeString LogType = iota
LogTypeSnapshot
LogTypeHealth
LogTypeInit
LogTypeStatus
)
// String implements the fmt.Stringer interface for LogType.
func (l LogType) String() string {
var typeString string
switch l {
case LogTypeString:
typeString = "string"
case LogTypeSnapshot:
typeString = "snapshot"
case LogTypeHealth:
typeString = "health"
case LogTypeInit:
typeString = "init"
case LogTypeStatus:
typeString = "status"
default:
typeString = "unknown"
}
return typeString
}