github.com/Uptycs/basequery-go@v0.8.0/plugin/logger/logger.go (about) 1 // Package logger creates an osquery logging plugin. 2 // 3 // See https://osquery.readthedocs.io/en/latest/development/logger-plugins/ for more. 4 package logger 5 6 import ( 7 "bytes" 8 "context" 9 "encoding/json" 10 11 "github.com/Uptycs/basequery-go/gen/osquery" 12 ) 13 14 // LogFunc is the logger function used by an osquery Logger plugin. 15 // 16 // The LogFunc should log the provided result string. The LogType 17 // argument can be optionally used to log differently depending on the 18 // type of log received. The context argument can optionally be used 19 // for cancellation in long-running operations. 20 type LogFunc func(ctx context.Context, typ LogType, log string) error 21 22 // Plugin is an osquery logger plugin. 23 // The Plugin struct implements the OsqueryPlugin interface. 24 type Plugin struct { 25 name string 26 logFn LogFunc 27 } 28 29 // NewPlugin takes a value that implements LoggerPlugin and wraps it with 30 // the appropriate methods to satisfy the OsqueryPlugin interface. Use this to 31 // easily create plugins implementing osquery loggers. 32 func NewPlugin(name string, fn LogFunc) *Plugin { 33 return &Plugin{name: name, logFn: fn} 34 } 35 36 // Name returns the logger plugin name. 37 func (t *Plugin) Name() string { 38 return t.name 39 } 40 41 // RegistryName always returns static string "logger" for logger plugins. 42 func (t *Plugin) RegistryName() string { 43 return "logger" 44 } 45 46 // Routes returns empty plugin response for logger plugins. 47 func (t *Plugin) Routes() osquery.ExtensionPluginResponse { 48 return []map[string]string{} 49 } 50 51 // Ping returns static "OK" response. 52 func (t *Plugin) Ping() osquery.ExtensionStatus { 53 return osquery.ExtensionStatus{Code: 0, Message: "OK"} 54 } 55 56 // Call is invoked to log the specified request details. Depending on the type of logger implementation, 57 // contents of the requests can be saved to a file, sent to remote destination etc after necessary formatting. 58 func (t *Plugin) Call(ctx context.Context, request osquery.ExtensionPluginRequest) osquery.ExtensionResponse { 59 var err error 60 if log, ok := request["string"]; ok { 61 err = t.logFn(ctx, LogTypeString, log) 62 } else if log, ok := request["snapshot"]; ok { 63 err = t.logFn(ctx, LogTypeSnapshot, log) 64 } else if log, ok := request["health"]; ok { 65 err = t.logFn(ctx, LogTypeHealth, log) 66 } else if log, ok := request["init"]; ok { 67 err = t.logFn(ctx, LogTypeInit, log) 68 } else if _, ok := request["status"]; ok { 69 statusJSON := []byte(request["log"]) 70 if len(statusJSON) == 0 { 71 return osquery.ExtensionResponse{ 72 Status: &osquery.ExtensionStatus{ 73 Code: 1, 74 Message: "got empty status", 75 }, 76 } 77 } 78 79 // Dirty hack because osquery gives us malformed JSON. 80 statusJSON = bytes.Replace(statusJSON, []byte(`"":`), []byte(``), -1) 81 statusJSON[0] = '[' 82 statusJSON[len(statusJSON)-1] = ']' 83 84 var parsedStatuses []json.RawMessage 85 if err := json.Unmarshal(statusJSON, &parsedStatuses); err != nil { 86 return osquery.ExtensionResponse{ 87 Status: &osquery.ExtensionStatus{ 88 Code: 1, 89 Message: "error parsing status logs: " + err.Error(), 90 }, 91 } 92 } 93 94 for _, s := range parsedStatuses { 95 err = t.logFn(ctx, LogTypeStatus, string(s)) 96 } 97 } else { 98 return osquery.ExtensionResponse{ 99 Status: &osquery.ExtensionStatus{ 100 Code: 1, 101 Message: "unknown log request", 102 }, 103 } 104 } 105 106 if err != nil { 107 return osquery.ExtensionResponse{ 108 Status: &osquery.ExtensionStatus{ 109 Code: 1, 110 Message: "error logging: " + err.Error(), 111 }, 112 } 113 } 114 115 return osquery.ExtensionResponse{ 116 Status: &osquery.ExtensionStatus{Code: 0, Message: "OK"}, 117 Response: osquery.ExtensionPluginResponse{}, 118 } 119 } 120 121 // Shutdown is a no-op function for logger plugins. 122 func (t *Plugin) Shutdown() {} 123 124 //LogType encodes the type of log osquery is outputting. 125 type LogType int 126 127 const ( 128 // LogTypeString to log a string 129 LogTypeString LogType = iota 130 // LogTypeSnapshot to log snapshot results 131 LogTypeSnapshot 132 // LogTypeHealth for health details logging 133 LogTypeHealth 134 // LogTypeInit for init details logging 135 LogTypeInit 136 // LogTypeStatus for differential results status logging 137 LogTypeStatus 138 ) 139 140 // String implements the fmt.Stringer interface for LogType. 141 func (l LogType) String() string { 142 var typeString string 143 switch l { 144 case LogTypeString: 145 typeString = "string" 146 case LogTypeSnapshot: 147 typeString = "snapshot" 148 case LogTypeHealth: 149 typeString = "health" 150 case LogTypeInit: 151 typeString = "init" 152 case LogTypeStatus: 153 typeString = "status" 154 default: 155 typeString = "unknown" 156 } 157 return typeString 158 }