fix: use zerolog for orbit osquery table logging (#20028)

> Related issue: #19886 

# Checklist for submitter

If some of the following don't apply, delete the relevant line.

<!-- Note that API documentation changes are now addressed by the
product design team. -->

- [x] Changes file added for user-visible changes in `changes/`,
`orbit/changes/` or `ee/fleetd-chrome/changes`.
See [Changes
files](https://fleetdm.com/docs/contributing/committing-changes#changes-files)
for more information.
- [x] Added/updated tests
- [x] Manual QA for all new/changed functionality
  - For Orbit and Fleet Desktop changes:
- [x] Manual QA must be performed in the three main OSs, macOS, Windows
and Linux.
- [x] Auto-update manual QA, from released version of component to new
version (see [tools/tuf/test](../tools/tuf/test/README.md)).
This commit is contained in:
Jahziel Villasana-Espinoza
2024-06-27 13:26:20 -04:00
committed by GitHub
parent 0c75908ae4
commit 87f4a28419
27 changed files with 184 additions and 267 deletions
+1
View File
@@ -0,0 +1 @@
- Fixes a bug that caused log Orbit's osquery table log output to be inconsistent.
+41 -48
View File
@@ -47,9 +47,8 @@ import (
"time"
"unicode/utf8"
"github.com/go-kit/log"
"github.com/go-kit/log/level"
"github.com/groob/plist"
"github.com/rs/zerolog"
howett "howett.net/plist"
)
@@ -70,7 +69,7 @@ type Flattener struct {
expandNestedPlist bool
includeNestedRaw bool
includeNils bool
logger log.Logger
logger zerolog.Logger
query []string
queryKeyDenoter string
queryWildcard string
@@ -95,11 +94,7 @@ func WithNestedPlist() FlattenOpts {
}
// WithLogger sets the logger to use
func WithLogger(logger log.Logger) FlattenOpts {
if logger == nil {
return func(_ *Flattener) {}
}
func WithLogger(logger zerolog.Logger) FlattenOpts {
return func(fl *Flattener) {
fl.logger = logger
}
@@ -132,7 +127,7 @@ func WithQuery(q []string) FlattenOpts {
func Flatten(data interface{}, opts ...FlattenOpts) ([]Row, error) {
fl := &Flattener{
rows: []Row{},
logger: log.NewNopLogger(),
logger: zerolog.Nop(),
queryWildcard: `*`,
queryKeyDenoter: `#`,
}
@@ -142,7 +137,7 @@ func Flatten(data interface{}, opts ...FlattenOpts) ([]Row, error) {
}
if !fl.debugLogging {
fl.logger = level.NewFilter(fl.logger, level.AllowInfo())
fl.logger = fl.logger.Level(zerolog.InfoLevel)
}
if err := fl.descend([]string{}, data, 0); err != nil {
@@ -155,20 +150,19 @@ func Flatten(data interface{}, opts ...FlattenOpts) ([]Row, error) {
// descend recurses through a given data structure flattening along the way.
func (fl *Flattener) descend(path []string, data interface{}, depth int) error {
queryTerm, isQueryMatched := fl.queryAtDepth(depth)
logger := log.With(fl.logger,
"caller", "descend",
"depth", depth,
"rows-so-far", len(fl.rows),
"query", queryTerm,
"path", strings.Join(path, "/"),
)
logger := fl.logger.With().
Str("caller", "descend").
Int("depth", depth).
Int("rows-so-far", len(fl.rows)).
Str("query", queryTerm).
Str("path", strings.Join(path, "/")).
Logger()
switch v := data.(type) {
case []interface{}:
for i, e := range v {
pathKey := strconv.Itoa(i)
level.Debug(logger).Log("msg", "checking an array", "indexStr", pathKey)
logger.Debug().Str("indexStr", pathKey).Msg("checking an array")
// If the queryTerm starts with
// queryKeyDenoter, then we want to rewrite
@@ -184,25 +178,25 @@ func (fl *Flattener) descend(path []string, data interface{}, depth int) error {
keyQuery := strings.SplitN(strings.TrimPrefix(queryTerm, fl.queryKeyDenoter), "=>", 2)
keyName := keyQuery[0]
innerlogger := log.With(logger, "arraykeyname", keyName)
level.Debug(logger).Log("msg", "attempting to coerce array into map")
innerlogger := logger.With().Str("arraykeyname", keyName).Logger()
logger.Debug().Msg("attempting to coerce array into map")
e, ok := e.(map[string]interface{})
if !ok {
level.Debug(innerlogger).Log("msg", "can't coerce into map")
innerlogger.Debug().Msg("can't coerce into map")
continue
}
// Is keyName in this array?
val, ok := e[keyName]
if !ok {
level.Debug(innerlogger).Log("msg", "keyName not in map")
innerlogger.Debug().Msg("keyName not in map")
continue
}
pathKey, ok = val.(string)
if !ok {
level.Debug(innerlogger).Log("msg", "can't coerce pathKey val into string")
innerlogger.Debug().Msg("can't coerce pathKey val into string")
continue
}
@@ -210,7 +204,7 @@ func (fl *Flattener) descend(path []string, data interface{}, depth int) error {
}
if !(isQueryMatched || fl.queryMatchArrayElement(e, i, queryTerm)) {
level.Debug(logger).Log("msg", "query not matched")
logger.Debug().Msg("query not matched")
continue
}
@@ -219,7 +213,7 @@ func (fl *Flattener) descend(path []string, data interface{}, depth int) error {
}
}
case map[string]interface{}:
level.Debug(logger).Log("msg", "checking a map")
logger.Debug().Msg("checking a map")
for k, e := range v {
// Check that the key name matches. If not, skip this entire
// branch of the map
@@ -232,7 +226,7 @@ func (fl *Flattener) descend(path []string, data interface{}, depth int) error {
}
}
case []map[string]interface{}:
level.Debug(logger).Log("msg", "checking an array of maps")
logger.Debug().Msg("checking an array of maps")
for i, e := range v {
if err := fl.descend(append(path, strconv.Itoa(i)), e, depth+1); err != nil {
return fmt.Errorf("flattening array of maps: %w", err)
@@ -241,7 +235,7 @@ func (fl *Flattener) descend(path []string, data interface{}, depth int) error {
case nil:
// Because we want to filter nils out, we do _not_ examine isQueryMatched here
if !(fl.queryMatchNil(queryTerm)) {
level.Debug(logger).Log("msg", "query not matched")
logger.Debug().Msg("query not matched")
return nil
}
fl.rows = append(fl.rows, NewRow(path, ""))
@@ -261,7 +255,7 @@ func (fl *Flattener) descend(path []string, data interface{}, depth int) error {
// handleStringLike is called when we finally have an object we think
// can be converted to a string. It uses the depth to compare against
// the query, and returns a stringify'ed value
func (fl *Flattener) handleStringLike(logger log.Logger, path []string, v interface{}, depth int) error {
func (fl *Flattener) handleStringLike(logger zerolog.Logger, path []string, v interface{}, depth int) error {
queryTerm, isQueryMatched := fl.queryAtDepth(depth)
stringValue, err := stringify(v)
@@ -270,7 +264,7 @@ func (fl *Flattener) handleStringLike(logger log.Logger, path []string, v interf
}
if !(isQueryMatched || fl.queryMatchString(stringValue, queryTerm)) {
level.Debug(logger).Log("msg", "query not matched")
logger.Debug().Msg("query not matched")
return nil
}
@@ -282,12 +276,12 @@ func (fl *Flattener) handleStringLike(logger log.Logger, path []string, v interf
// embedded plist. In the case of failures, it falls back to treating
// it like a plain string.
func (fl *Flattener) descendMaybePlist(path []string, data []byte, depth int) error {
logger := log.With(fl.logger,
"caller", "descendMaybePlist",
"depth", depth,
"rows-so-far", len(fl.rows),
"path", strings.Join(path, "/"),
)
logger := fl.logger.With().
Str("caller", "descendMaybePlist").
Int("depth", depth).
Int("rows-so-far", len(fl.rows)).
Str("path", strings.Join(path, "/")).
Logger()
// Skip if we're not expanding nested plists
if !fl.expandNestedPlist {
@@ -300,19 +294,19 @@ func (fl *Flattener) descendMaybePlist(path []string, data []byte, depth int) er
}
// Looks like a plist. Try parsing it
level.Debug(logger).Log("msg", "Parsing inner plist")
logger.Debug().Msg("Parsing inner plist")
var innerData interface{}
if err := plist.Unmarshal(data, &innerData); err != nil {
level.Info(logger).Log("msg", "plist parsing failed", "err", err)
logger.Info().Err(err).Msg("plist parsing failed")
return fl.handleStringLike(logger, path, data, depth)
}
// have a parsed plist. Descend and return from here.
if fl.includeNestedRaw {
if err := fl.handleStringLike(logger, append(path, "_raw"), data, depth); err != nil {
level.Error(logger).Log("msg", "Failed to add _raw key", "err", err)
logger.Error().Err(err).Msg("Failed to add _raw key")
}
}
@@ -338,12 +332,12 @@ func (fl *Flattener) queryMatchNil(queryTerm string) bool {
// We use `=>` as something that is reasonably intuitive, and not very
// likely to occur on it's own. Unfortunately, `==` shows up in base64
func (fl *Flattener) queryMatchArrayElement(data interface{}, arrIndex int, queryTerm string) bool {
logger := log.With(fl.logger,
"caller", "queryMatchArrayElement",
"rows-so-far", len(fl.rows),
"query", queryTerm,
"arrIndex", arrIndex,
)
logger := fl.logger.With().
Str("caller", "queryMatchArrayElement").
Int("rows-so-far", len(fl.rows)).
Str("query", queryTerm).
Int("arrIndex", arrIndex).
Logger()
// strip off the key re-write denotation before trying to match
queryTerm = strings.TrimPrefix(queryTerm, fl.queryKeyDenoter)
@@ -354,11 +348,11 @@ func (fl *Flattener) queryMatchArrayElement(data interface{}, arrIndex int, quer
// If the queryTerm is an int, then we expect to match the index
if queryIndex, err := strconv.Atoi(queryTerm); err == nil {
level.Debug(logger).Log("msg", "using numeric index comparison")
logger.Debug().Msg("using numeric index comparison")
return queryIndex == arrIndex
}
level.Debug(logger).Log("msg", "checking data type")
logger.Debug().Msg("checking data type")
switch dataCasted := data.(type) {
case []interface{}:
@@ -407,7 +401,6 @@ func (fl *Flattener) queryMatchStringify(data interface{}, queryTerm string) boo
}
return fl.queryMatchString(stringValue, queryTerm)
}
func (fl *Flattener) queryMatchString(v, queryTerm string) bool {
@@ -7,18 +7,19 @@ import (
"regexp"
"github.com/fleetdm/fleet/v4/orbit/pkg/table/tablehelpers"
"github.com/go-kit/log"
"github.com/go-kit/log/level"
"github.com/osquery/osquery-go/plugin/table"
"github.com/rs/zerolog"
)
const kernelCheckUtilPath = "/opt/CrowdStrike/falcon-kernel-check"
type Table struct {
logger log.Logger
logger zerolog.Logger
name string
}
func TablePlugin(logger log.Logger) *table.Plugin {
func TablePlugin(logger zerolog.Logger) *table.Plugin {
columns := []table.ColumnDefinition{
table.TextColumn("kernel"),
table.IntegerColumn("supported"),
@@ -26,9 +27,9 @@ func TablePlugin(logger log.Logger) *table.Plugin {
}
tableName := "falcon_kernel_check"
t := &Table{
logger: log.With(logger, "table", tableName),
name: tableName,
logger: logger.With().Str("table", tableName).Logger(),
}
return table.NewPlugin(tableName, columns, t.generate)
@@ -37,13 +38,13 @@ func TablePlugin(logger log.Logger) *table.Plugin {
func (t *Table) generate(ctx context.Context, queryContext table.QueryContext) ([]map[string]string, error) {
output, err := tablehelpers.Exec(ctx, t.logger, 5, []string{kernelCheckUtilPath}, []string{}, false)
if err != nil {
level.Info(t.logger).Log("msg", "exec failed", "err", err)
t.logger.Info().Str("table", t.name).Err(err).Msg("exec failed")
return nil, err
}
status, err := parseStatus(string(output))
if err != nil {
level.Info(t.logger).Log("msg", "Error parsing exec status", "err", err)
t.logger.Info().Str("table", t.name).Err(err).Msg("Error parsing exec status")
return nil, err
}
+10 -11
View File
@@ -10,9 +10,8 @@ import (
"github.com/fleetdm/fleet/v4/orbit/pkg/dataflatten"
"github.com/fleetdm/fleet/v4/orbit/pkg/table/dataflattentable"
"github.com/fleetdm/fleet/v4/orbit/pkg/table/tablehelpers"
"github.com/go-kit/log"
"github.com/go-kit/log/level"
"github.com/osquery/osquery-go/plugin/table"
"github.com/rs/zerolog"
)
var (
@@ -37,21 +36,21 @@ var (
defaultOption = strings.Join(allowedOptions, " ")
)
type execFunc func(context.Context, log.Logger, int, []string, []string, bool) ([]byte, error)
type execFunc func(context.Context, zerolog.Logger, int, []string, []string, bool) ([]byte, error)
type falconctlOptionsTable struct {
logger log.Logger
logger zerolog.Logger
tableName string
execFunc execFunc
}
func NewFalconctlOptionTable(logger log.Logger) *table.Plugin {
func NewFalconctlOptionTable(logger zerolog.Logger) *table.Plugin {
columns := dataflattentable.Columns(
table.TextColumn("options"),
)
t := &falconctlOptionsTable{
logger: log.With(logger, "table", "falconctl_options"),
logger: logger.With().Str("table", "falconctl_options").Logger(),
tableName: "falconctl_options",
execFunc: tablehelpers.Exec,
}
@@ -77,7 +76,7 @@ OUTER:
for _, option := range options {
option = strings.Trim(option, " ")
if !optionAllowed(option) {
level.Info(t.logger).Log("msg", "requested option not allowed", "option", option)
t.logger.Info().Msgf("requested option not allowed: %s", option)
continue OUTER
}
}
@@ -90,14 +89,14 @@ OUTER:
output, err := t.execFunc(ctx, t.logger, 30, falconctlPaths, args, false)
if err != nil {
level.Info(t.logger).Log("msg", "exec failed", "err", err)
t.logger.Info().Err(err).Msg("exec failed")
synthesizedData := map[string]string{
"_error": fmt.Sprintf("falconctl parse failure: %s", err),
}
flattened, err := dataflatten.Flatten(synthesizedData)
if err != nil {
level.Info(t.logger).Log("msg", "failure flattening output", "err", err)
t.logger.Info().Err(err).Msg("failure flattening output")
continue
}
@@ -107,7 +106,7 @@ OUTER:
parsed, err := parseOptions(bytes.NewReader(output))
if err != nil {
level.Info(t.logger).Log("msg", "parse failed", "err", err)
t.logger.Info().Err(err).Msg("parse failed")
parsed = map[string]string{
"_error": fmt.Sprintf("falconctl parse failure: %s", err),
}
@@ -121,7 +120,7 @@ OUTER:
flattened, err := dataflatten.Flatten(parsed, flattenOpts...)
if err != nil {
level.Info(t.logger).Log("msg", "failure flattening output", "err", err)
t.logger.Info().Err(err).Msg("failure flattening output")
continue
}
@@ -8,7 +8,7 @@ import (
"testing"
"github.com/fleetdm/fleet/v4/orbit/pkg/table/tablehelpers"
"github.com/go-kit/log"
"github.com/rs/zerolog"
"github.com/stretchr/testify/require"
)
@@ -62,7 +62,7 @@ func TestOptionRestrictions(t *testing.T) {
var logBytes bytes.Buffer
testTable := &falconctlOptionsTable{
logger: log.NewLogfmtLogger(&logBytes),
logger: zerolog.New(zerolog.ConsoleWriter{Out: &logBytes}),
execFunc: noopExec,
}
@@ -82,7 +82,7 @@ func TestOptionRestrictions(t *testing.T) {
}
}
func noopExec(_ context.Context, log log.Logger, _ int, _ []string, args []string, _ bool) ([]byte, error) {
log.Log("exec", "exec-in-test", "args", strings.Join(args, " "))
func noopExec(_ context.Context, log zerolog.Logger, _ int, _ []string, args []string, _ bool) ([]byte, error) {
log.Info().Str("args", strings.Join(args, " ")).Msg("exec-in-test")
return []byte{}, nil
}
+6 -11
View File
@@ -14,23 +14,22 @@ import (
"github.com/fleetdm/fleet/v4/orbit/pkg/dataflatten"
"github.com/fleetdm/fleet/v4/orbit/pkg/table/dataflattentable"
"github.com/fleetdm/fleet/v4/orbit/pkg/table/tablehelpers"
"github.com/go-kit/log"
"github.com/go-kit/log/level"
"github.com/osquery/osquery-go/plugin/table"
"github.com/rs/zerolog"
)
type Table struct {
logger log.Logger
logger zerolog.Logger
}
func TablePlugin(logger log.Logger) *table.Plugin {
func TablePlugin(logger zerolog.Logger) *table.Plugin {
columns := dataflattentable.Columns(
table.TextColumn("passphrase"),
table.TextColumn("path"),
)
t := &Table{
logger: logger,
logger: logger.With().Str("table", "cryptoinfo").Logger(),
}
return table.NewPlugin("cryptoinfo", columns, t.generate)
@@ -49,7 +48,7 @@ func (t *Table) generate(ctx context.Context, queryContext table.QueryContext) (
// We take globs in via the sql %, but glob needs *. So convert.
filePaths, err := filepath.Glob(strings.ReplaceAll(requestedPath, `%`, `*`))
if err != nil {
level.Info(t.logger).Log("msg", "bad file glob", "err", err)
t.logger.Info().Err(err).Msg("bad file glob")
continue
}
@@ -65,11 +64,7 @@ func (t *Table) generate(ctx context.Context, queryContext table.QueryContext) (
flatData, err := flattenCryptoInfo(filePath, passphrase, flattenOpts...)
if err != nil {
level.Info(t.logger).Log(
"msg", "failed to get data for path",
"path", filePath,
"err", err,
)
t.logger.Info().Err(err).Str("path", filePath).Msg("failed to get data for path")
continue
}
+7 -8
View File
@@ -9,9 +9,8 @@ import (
"github.com/fleetdm/fleet/v4/orbit/pkg/dataflatten"
"github.com/fleetdm/fleet/v4/orbit/pkg/table/dataflattentable"
"github.com/fleetdm/fleet/v4/orbit/pkg/table/tablehelpers"
"github.com/go-kit/log"
"github.com/go-kit/log/level"
"github.com/osquery/osquery-go/plugin/table"
"github.com/rs/zerolog"
)
var cryptsetupPaths = []string{
@@ -22,17 +21,17 @@ var cryptsetupPaths = []string{
const allowedNameCharacters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-/_"
type Table struct {
logger log.Logger
logger zerolog.Logger
name string
}
func TablePlugin(logger log.Logger) *table.Plugin {
func TablePlugin(logger zerolog.Logger) *table.Plugin {
columns := dataflattentable.Columns(
table.TextColumn("name"),
)
t := &Table{
logger: logger,
logger: logger.With().Str("table", "cryptsetup_status").Logger(),
name: "cryptsetup_status",
}
@@ -54,20 +53,20 @@ func (t *Table) generate(ctx context.Context, queryContext table.QueryContext) (
for _, name := range requestedNames {
output, err := tablehelpers.Exec(ctx, t.logger, 15, cryptsetupPaths, []string{"--readonly", "status", name}, false)
if err != nil {
level.Debug(t.logger).Log("msg", "Error execing for status", "name", name, "err", err)
t.logger.Debug().Err(err).Str("name", name).Msg("Error execing for status")
continue
}
status, err := parseStatus(output)
if err != nil {
level.Info(t.logger).Log("msg", "Error parsing status", "name", name, "err", err)
t.logger.Info().Err(err).Str("name", name).Msg("Error parsing status")
continue
}
for _, dataQuery := range tablehelpers.GetConstraints(queryContext, "query", tablehelpers.WithDefaults("*")) {
flatData, err := t.flattenOutput(dataQuery, status)
if err != nil {
level.Info(t.logger).Log("msg", "flatten failed", "err", err)
t.logger.Info().Err(err).Msg("flatten failed")
continue
}
+6 -7
View File
@@ -14,9 +14,8 @@ import (
"github.com/fleetdm/fleet/v4/orbit/pkg/dataflatten"
"github.com/fleetdm/fleet/v4/orbit/pkg/table/tablehelpers"
"github.com/go-kit/log"
"github.com/go-kit/log/level"
"github.com/osquery/osquery-go/plugin/table"
"github.com/rs/zerolog"
)
type ExecTableOpt func(*Table)
@@ -35,11 +34,11 @@ func WithBinDirs(binDirs ...string) ExecTableOpt {
}
}
func TablePluginExec(logger log.Logger, tableName string, dataSourceType DataSourceType, execArgs []string, opts ...ExecTableOpt) *table.Plugin {
func TablePluginExec(logger zerolog.Logger, tableName string, dataSourceType DataSourceType, execArgs []string, opts ...ExecTableOpt) *table.Plugin {
columns := Columns()
t := &Table{
logger: level.NewFilter(logger, level.AllowInfo()),
logger: logger.With().Str("table", tableName).Logger(),
tableName: tableName,
execArgs: execArgs,
keyValueSeparator: ":",
@@ -77,7 +76,7 @@ func (t *Table) generateExec(ctx context.Context, queryContext table.QueryContex
// If the exec failed for some reason, it's probably better to return no results, and log the,
// error. Returning an error here will cause a table failure, and thus break joins
level.Info(t.logger).Log("msg", "failed to exec", "err", err)
t.logger.Info().Err(err).Msg("failed to exec")
return nil, nil
}
@@ -89,7 +88,7 @@ func (t *Table) generateExec(ctx context.Context, queryContext table.QueryContex
flattened, err := t.flattenBytesFunc(execBytes, flattenOpts...)
if err != nil {
level.Info(t.logger).Log("msg", "failure flattening output", "err", err)
t.logger.Info().Err(err).Msg("failure flattening output")
continue
}
@@ -121,7 +120,7 @@ func (t *Table) exec(ctx context.Context) ([]byte, error) {
cmd.Stdout = &stdout
cmd.Stderr = &stderr
level.Debug(t.logger).Log("msg", "calling %s", "args", cmd.String())
t.logger.Debug().Str("args", strings.Join(t.execArgs[1:], " ")).Msgf("calling %s", cmd.String())
if err := cmd.Run(); os.IsNotExist(err) {
// try the next binary
+6 -11
View File
@@ -9,10 +9,9 @@ import (
"github.com/fleetdm/fleet/v4/orbit/pkg/dataflatten"
"github.com/fleetdm/fleet/v4/orbit/pkg/table/tablehelpers"
"github.com/go-kit/log"
"github.com/go-kit/log/level"
"github.com/osquery/osquery-go"
"github.com/osquery/osquery-go/plugin/table"
"github.com/rs/zerolog"
)
type DataSourceType int
@@ -28,7 +27,7 @@ const (
)
type Table struct {
logger log.Logger
logger zerolog.Logger
tableName string
flattenFileFunc func(string, ...dataflatten.FlattenOpts) ([]dataflatten.Row, error)
@@ -41,7 +40,7 @@ type Table struct {
}
// AllTablePlugins is a helper to return all the expected flattening tables.
func AllTablePlugins(logger log.Logger) []osquery.OsqueryPlugin {
func AllTablePlugins(logger zerolog.Logger) []osquery.OsqueryPlugin {
return []osquery.OsqueryPlugin{
TablePlugin(logger, JsonType),
TablePlugin(logger, XmlType),
@@ -51,7 +50,7 @@ func AllTablePlugins(logger log.Logger) []osquery.OsqueryPlugin {
}
}
func TablePlugin(logger log.Logger, dataSourceType DataSourceType) osquery.OsqueryPlugin {
func TablePlugin(logger zerolog.Logger, dataSourceType DataSourceType) osquery.OsqueryPlugin {
columns := Columns(table.TextColumn("path"))
t := &Table{
@@ -101,11 +100,7 @@ func (t *Table) generate(ctx context.Context, queryContext table.QueryContext) (
for _, dataQuery := range tablehelpers.GetConstraints(queryContext, "query", tablehelpers.WithDefaults("*")) {
subresults, err := t.generatePath(filePath, dataQuery)
if err != nil {
level.Info(t.logger).Log(
"msg", "failed to get data for path",
"path", filePath,
"err", err,
)
t.logger.Info().Err(err).Str("path", filePath).Msg("failed to get data for path")
continue
}
@@ -125,7 +120,7 @@ func (t *Table) generatePath(filePath string, dataQuery string) ([]map[string]st
data, err := t.flattenFileFunc(filePath, flattenOpts...)
if err != nil {
level.Info(t.logger).Log("msg", "failure parsing file", "file", filePath)
t.logger.Info().Err(err).Str("file", filePath).Msg("failure parsing file")
return nil, fmt.Errorf("parsing data: %w", err)
}
@@ -11,7 +11,7 @@ import (
"github.com/fleetdm/fleet/v4/orbit/pkg/dataflatten"
"github.com/fleetdm/fleet/v4/orbit/pkg/table/tablehelpers"
"github.com/go-kit/log"
"github.com/rs/zerolog"
"github.com/stretchr/testify/require"
)
@@ -21,7 +21,7 @@ import (
func TestDataFlattenTablePlist_Animals(t *testing.T) {
t.Parallel()
logger := log.NewNopLogger()
logger := zerolog.Nop()
// Test plist parsing both the json and xml forms
testTables := map[string]Table{
@@ -85,7 +85,7 @@ func TestDataFlattenTablePlist_Animals(t *testing.T) {
func TestDataFlattenTables(t *testing.T) {
t.Parallel()
logger := log.NewNopLogger()
logger := zerolog.Nop()
tests := []struct {
testTables map[string]Table
+9 -11
View File
@@ -50,9 +50,6 @@ type PluginOpts struct {
Socket string
}
// Logger for osquery tables
var osqueryLogger *Logger
// WithExtension registers the given Extension on the Runner.
func WithExtension(t Extension) Opt {
return func(r *Runner) {
@@ -73,8 +70,6 @@ func NewRunner(socket string, opts ...Opt) *Runner {
func (r *Runner) Execute() error {
log.Debug().Msg("start osquery extension")
osqueryLogger = NewOsqueryLogger()
if err := waitExtensionSocket(r.socket, 1*time.Minute); err != nil {
return err
}
@@ -146,14 +141,17 @@ func OrbitDefaultTables() []osquery.OsqueryPlugin {
table.NewPlugin("sntp_request", sntp_request.Columns(), sntp_request.GenerateFunc),
fleetd_logs.TablePlugin(),
firefox_preferences.TablePlugin(osqueryLogger),
cryptoinfotable.TablePlugin(osqueryLogger),
// Note: the logger passed here and to all other tables is the global logger from zerolog.
// This logger has already been configured with some required settings in
// orbit/cmd/orbit/orbit.go.
firefox_preferences.TablePlugin(log.Logger),
cryptoinfotable.TablePlugin(log.Logger),
// Additional data format tables
dataflattentable.TablePlugin(osqueryLogger, dataflattentable.JsonType), // table name is "parse_json"
dataflattentable.TablePlugin(osqueryLogger, dataflattentable.JsonlType), // table name is "parse_jsonl"
dataflattentable.TablePlugin(osqueryLogger, dataflattentable.XmlType), // table name is "parse_xml"
dataflattentable.TablePlugin(osqueryLogger, dataflattentable.IniType), // table name is "parse_ini"
dataflattentable.TablePlugin(log.Logger, dataflattentable.JsonType), // table name is "parse_json"
dataflattentable.TablePlugin(log.Logger, dataflattentable.JsonlType), // table name is "parse_jsonl"
dataflattentable.TablePlugin(log.Logger, dataflattentable.XmlType), // table name is "parse_xml"
dataflattentable.TablePlugin(log.Logger, dataflattentable.IniType), // table name is "parse_ini"
}
return plugins
+5 -4
View File
@@ -25,6 +25,7 @@ import (
"github.com/fleetdm/fleet/v4/orbit/pkg/table/sudo_info"
"github.com/fleetdm/fleet/v4/orbit/pkg/table/tcc_access"
"github.com/fleetdm/fleet/v4/orbit/pkg/table/user_login_settings"
"github.com/rs/zerolog/log"
"github.com/macadmins/osquery-extension/tables/filevaultusers"
"github.com/macadmins/osquery-extension/tables/macos_profiles"
@@ -83,14 +84,14 @@ func PlatformTables(opts PluginOpts) ([]osquery.OsqueryPlugin, error) {
},
),
filevault_status.TablePlugin(osqueryLogger), // table name is "filevault_status"
ioreg.TablePlugin(osqueryLogger), // table name is "ioreg"
filevault_status.TablePlugin(log.Logger), // table name is "filevault_status"
ioreg.TablePlugin(log.Logger), // table name is "ioreg"
// firmwarepasswd table. Only returns valid data on a Mac with an Intel processor. Background: https://support.apple.com/en-us/HT204455
firmwarepasswd.TablePlugin(osqueryLogger), // table name is "firmwarepasswd"
firmwarepasswd.TablePlugin(log.Logger), // table name is "firmwarepasswd"
// Table for parsing Apple Property List files, which are typically stored in ~/Library/Preferences/
dataflattentable.TablePlugin(osqueryLogger, dataflattentable.PlistType), // table name is "parse_plist"
dataflattentable.TablePlugin(log.Logger, dataflattentable.PlistType), // table name is "parse_plist"
}
// append platform specific tables
+4 -3
View File
@@ -6,14 +6,15 @@ import (
"github.com/fleetdm/fleet/v4/orbit/pkg/table/crowdstrike/falcon_kernel_check"
"github.com/fleetdm/fleet/v4/orbit/pkg/table/crowdstrike/falconctl"
"github.com/fleetdm/fleet/v4/orbit/pkg/table/cryptsetup"
"github.com/rs/zerolog/log"
"github.com/osquery/osquery-go"
)
func PlatformTables(_ PluginOpts) ([]osquery.OsqueryPlugin, error) {
return []osquery.OsqueryPlugin{
cryptsetup.TablePlugin(osqueryLogger), // table name is "cryptsetup_status"
falconctl.NewFalconctlOptionTable(osqueryLogger), // table name is "falconctl_option"
falcon_kernel_check.TablePlugin(osqueryLogger), // table name is "falcon_kernel_check"
cryptsetup.TablePlugin(log.Logger), // table name is "cryptsetup_status"
falconctl.NewFalconctlOptionTable(log.Logger), // table name is "falconctl_option"
falcon_kernel_check.TablePlugin(log.Logger), // table name is "falcon_kernel_check"
}, nil
}
-26
View File
@@ -1,26 +0,0 @@
package table
import (
"fmt"
"github.com/rs/zerolog"
"github.com/rs/zerolog/log"
)
// Logger is a wrapper around zerolog, which we use for tables
// using the go-kit logger
type Logger struct {
zerolog.Logger
}
// Log logs a message, implementing log.Logger interface
func (l *Logger) Log(keyValuePairs ...interface{}) error {
log.Logger.Info().Msg(fmt.Sprint(keyValuePairs...))
return nil
}
// NewOsqueryLogger returns the Logger struct.
func NewOsqueryLogger() *Logger {
// Return a Logger struct with our global logger, and use the existing global config for the log level.
return &Logger{log.Logger}
}
+2 -1
View File
@@ -8,6 +8,7 @@ import (
cisaudit "github.com/fleetdm/fleet/v4/orbit/pkg/table/cis_audit"
mdmbridge "github.com/fleetdm/fleet/v4/orbit/pkg/table/mdm"
"github.com/fleetdm/fleet/v4/orbit/pkg/table/windowsupdatetable"
"github.com/rs/zerolog/log"
"golang.org/x/sys/windows/registry"
"github.com/osquery/osquery-go"
@@ -19,7 +20,7 @@ func PlatformTables(_ PluginOpts) ([]osquery.OsqueryPlugin, error) {
// Fleet tables
table.NewPlugin("cis_audit", cisaudit.Columns(), cisaudit.Generate),
windowsupdatetable.TablePlugin(windowsupdatetable.UpdatesTable, osqueryLogger), // table name is "windows_updates"
windowsupdatetable.TablePlugin(windowsupdatetable.UpdatesTable, log.Logger), // table name is "windows_updates"
}
windowsServer, err := IsWindowsServer()
@@ -14,24 +14,23 @@ import (
"strings"
"github.com/fleetdm/fleet/v4/orbit/pkg/table/tablehelpers"
"github.com/go-kit/log"
"github.com/go-kit/log/level"
"github.com/osquery/osquery-go/plugin/table"
"github.com/rs/zerolog"
)
const fdesetupPath = "/usr/bin/fdesetup"
type Table struct {
logger log.Logger
logger zerolog.Logger
}
func TablePlugin(logger log.Logger) *table.Plugin {
func TablePlugin(logger zerolog.Logger) *table.Plugin {
columns := []table.ColumnDefinition{
table.TextColumn("status"),
}
t := &Table{
logger: logger,
logger: logger.With().Str("table", "filevault_status").Logger(),
}
return table.NewPlugin("filevault_status", columns, t.generate)
@@ -40,7 +39,7 @@ func TablePlugin(logger log.Logger) *table.Plugin {
func (t *Table) generate(ctx context.Context, queryContext table.QueryContext) ([]map[string]string, error) {
output, err := tablehelpers.Exec(ctx, t.logger, 10, []string{fdesetupPath}, []string{"status"}, false)
if err != nil {
level.Info(t.logger).Log("msg", "fdesetup failed", "err", err)
t.logger.Info().Err(err).Msg("fdesetup failed")
// Don't error out if the binary isn't found
if errors.Is(err, os.ErrNotExist) {
+7 -22
View File
@@ -4,7 +4,6 @@ package firefox_preferences
import (
"bufio"
"context"
"fmt"
"os"
"regexp"
"strings"
@@ -12,14 +11,13 @@ import (
"github.com/fleetdm/fleet/v4/orbit/pkg/dataflatten"
"github.com/fleetdm/fleet/v4/orbit/pkg/table/dataflattentable"
"github.com/fleetdm/fleet/v4/orbit/pkg/table/tablehelpers"
"github.com/go-kit/log"
"github.com/go-kit/log/level"
"github.com/osquery/osquery-go/plugin/table"
"github.com/rs/zerolog"
)
type Table struct {
name string
logger log.Logger
logger zerolog.Logger
}
const tableName = "firefox_preferences"
@@ -36,14 +34,14 @@ const tableName = "firefox_preferences"
// https://github.com/hansmi/go-mozpref
var re = regexp.MustCompile(`^user_pref\("([^,]+)",\s*"?(.*?)"?\);$`)
func TablePlugin(logger log.Logger) *table.Plugin {
func TablePlugin(logger zerolog.Logger) *table.Plugin {
columns := dataflattentable.Columns(
table.TextColumn("path"),
)
t := &Table{
name: tableName,
logger: logger,
logger: logger.With().Str("table", tableName).Logger(),
}
return table.NewPlugin(t.name, columns, t.generate)
@@ -55,10 +53,7 @@ func (t *Table) generate(ctx context.Context, queryContext table.QueryContext) (
filePaths := tablehelpers.GetConstraints(queryContext, "path")
if len(filePaths) == 0 {
level.Info(t.logger).Log(
"msg", fmt.Sprintf("no path provided to %s", tableName),
"table", tableName,
)
t.logger.Info().Msgf("no path provided to %s", tableName)
return results, nil
}
@@ -70,12 +65,7 @@ func (t *Table) generate(ctx context.Context, queryContext table.QueryContext) (
file, err := os.Open(filePath)
if err != nil {
level.Info(t.logger).Log(
"msg", "failed to open file",
"table", tableName,
"path", filePath,
"err", err,
)
t.logger.Info().Err(err).Str("path", filePath).Msg("failed to open file")
continue
}
@@ -104,12 +94,7 @@ func (t *Table) generate(ctx context.Context, queryContext table.QueryContext) (
flatData, err := dataflatten.Flatten(rawKeyVals, flattenOpts...)
if err != nil {
level.Debug(t.logger).Log(
"msg", "failed to flatten data for path",
"table", tableName,
"path", filePath,
"err", err,
)
t.logger.Debug().Err(err).Str("path", filePath).Msg("failed to flatten data for path")
continue
}
@@ -9,7 +9,7 @@ import (
"testing"
"github.com/fleetdm/fleet/v4/orbit/pkg/table/tablehelpers"
"github.com/go-kit/log"
"github.com/rs/zerolog"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
@@ -49,7 +49,7 @@ func Test_generate(t *testing.T) {
},
}
table := Table{logger: log.NewNopLogger()}
table := Table{logger: zerolog.Nop()}
for _, tt := range tests {
tt := tt
@@ -14,17 +14,16 @@ import (
"strings"
"time"
"github.com/go-kit/log"
"github.com/go-kit/log/level"
"github.com/osquery/osquery-go/plugin/table"
"github.com/rs/zerolog"
)
type Table struct {
logger log.Logger
logger zerolog.Logger
parser *OutputParser
}
func TablePlugin(logger log.Logger) *table.Plugin {
func TablePlugin(logger zerolog.Logger) *table.Plugin {
columns := []table.ColumnDefinition{
table.IntegerColumn("option_roms_allowed"),
table.IntegerColumn("password_enabled"),
@@ -36,7 +35,7 @@ func TablePlugin(logger log.Logger) *table.Plugin {
return table.NewPlugin("firmwarepasswd", columns, t.generate)
}
func New(logger log.Logger) *Table {
func New(logger zerolog.Logger) *Table {
parser := NewParser(logger,
[]Matcher{
{
@@ -57,7 +56,7 @@ func New(logger log.Logger) *Table {
})
return &Table{
logger: level.NewFilter(logger, level.AllowInfo()),
logger: logger.With().Str("table", "firmwarepasswd").Logger(),
parser: parser,
}
}
@@ -68,11 +67,7 @@ func (t *Table) generate(ctx context.Context, queryContext table.QueryContext) (
for _, mode := range []string{"-check", "-mode"} {
output := new(bytes.Buffer)
if err := t.runFirmwarepasswd(ctx, mode, output); err != nil {
level.Info(t.logger).Log(
"msg", "Error running firmware password",
"command", mode,
"err", err,
)
t.logger.Info().Err(err).Str("command", mode).Msg("Error running firmware password")
continue
}
@@ -110,12 +105,12 @@ func (t *Table) runFirmwarepasswd(ctx context.Context, subcommand string, output
cmd.Stdout = output
if err := cmd.Run(); err != nil {
level.Debug(t.logger).Log(
"msg", "Error running firmwarepasswd",
"stderr", strings.TrimSpace(stderr.String()),
"stdout", strings.TrimSpace(output.String()),
"err", err,
)
t.logger.Debug().
Err(err).
Str("stderr", strings.TrimSpace(stderr.String())).
Str("stdout", strings.TrimSpace(output.String())).
Msg("Error running firmwarepasswd")
return fmt.Errorf("running firmwarepasswd: %w", err)
}
return nil
@@ -7,7 +7,7 @@ import (
"path/filepath"
"testing"
"github.com/go-kit/log"
"github.com/rs/zerolog"
"github.com/stretchr/testify/require"
)
@@ -48,7 +48,7 @@ func TestParser(t *testing.T) {
for _, tt := range tests {
tt := tt
parser := New(log.NewNopLogger()).parser
parser := New(zerolog.Nop()).parser
t.Run(tt.input, func(t *testing.T) {
t.Parallel()
+7 -16
View File
@@ -5,8 +5,7 @@ import (
"bufio"
"bytes"
"github.com/go-kit/log"
"github.com/go-kit/log/level"
"github.com/rs/zerolog"
)
type Matcher struct {
@@ -17,10 +16,10 @@ type Matcher struct {
type OutputParser struct {
matchers []Matcher
logger log.Logger
logger zerolog.Logger
}
func NewParser(logger log.Logger, matchers []Matcher) *OutputParser {
func NewParser(logger zerolog.Logger, matchers []Matcher) *OutputParser {
p := &OutputParser{
matchers: matchers,
logger: logger,
@@ -46,21 +45,13 @@ func (p *OutputParser) Parse(input *bytes.Buffer) []map[string]string {
if m.Match(line) {
key, err := m.KeyFunc(line)
if err != nil {
level.Debug(p.logger).Log(
"msg", "key match failed",
"line", line,
"err", err,
)
p.logger.Debug().Err(err).Str("line", line).Msg("key match failed")
continue
}
val, err := m.ValFunc(line)
if err != nil {
level.Debug(p.logger).Log(
"msg", "value match failed",
"line", line,
"err", err,
)
p.logger.Debug().Err(err).Str("line", line).Msg("value match failed")
continue
}
@@ -70,14 +61,14 @@ func (p *OutputParser) Parse(input *bytes.Buffer) []map[string]string {
}
if len(row) == 0 {
level.Debug(p.logger).Log("msg", "No matched keys", "line", line)
p.logger.Debug().Str("line", line).Msg("No matched keys")
continue
}
results = append(results, row)
}
if err := scanner.Err(); err != nil {
level.Debug(p.logger).Log("msg", "scanner error", "err", err)
p.logger.Debug().Err(err).Msg("scanner error")
}
return results
}
+7 -8
View File
@@ -17,9 +17,8 @@ import (
"github.com/fleetdm/fleet/v4/orbit/pkg/dataflatten"
"github.com/fleetdm/fleet/v4/orbit/pkg/table/dataflattentable"
"github.com/fleetdm/fleet/v4/orbit/pkg/table/tablehelpers"
"github.com/go-kit/log"
"github.com/go-kit/log/level"
"github.com/osquery/osquery-go/plugin/table"
"github.com/rs/zerolog"
)
const ioregPath = "/usr/sbin/ioreg"
@@ -27,11 +26,11 @@ const ioregPath = "/usr/sbin/ioreg"
const allowedCharacters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
type Table struct {
logger log.Logger
tableName string
logger zerolog.Logger
}
func TablePlugin(logger log.Logger) *table.Plugin {
func TablePlugin(logger zerolog.Logger) *table.Plugin {
columns := dataflattentable.Columns(
// ioreg input options. These match the ioreg
// command line. See the ioreg man page.
@@ -44,8 +43,8 @@ func TablePlugin(logger log.Logger) *table.Plugin {
)
t := &Table{
logger: logger,
tableName: "ioreg",
logger: logger.With().Str("table", "ioreg").Logger(),
}
return table.NewPlugin(t.tableName, columns, t.generate)
@@ -94,7 +93,7 @@ func (t *Table) generate(ctx context.Context, queryContext table.QueryContext) (
case "1":
ioregArgs = append(ioregArgs, "-r")
default:
level.Info(t.logger).Log("msg", "r should be blank, 0, or 1")
t.logger.Info().Msg("r should be blank, 0, or 1")
continue
}
@@ -103,13 +102,13 @@ func (t *Table) generate(ctx context.Context, queryContext table.QueryContext) (
ioregOutput, err := tablehelpers.Exec(ctx, t.logger, 30, []string{ioregPath}, ioregArgs, false)
if err != nil {
level.Info(t.logger).Log("msg", "ioreg failed", "err", err)
t.logger.Info().Err(err).Msg("ioreg failed ctx logger")
continue
}
flatData, err := t.flattenOutput(dataQuery, ioregOutput)
if err != nil {
level.Info(t.logger).Log("msg", "flatten failed", "err", err)
t.logger.Info().Err(err).Msg("flatten failed")
continue
}
+3 -7
View File
@@ -11,8 +11,7 @@ import (
"os/exec"
"time"
"github.com/go-kit/log"
"github.com/go-kit/log/level"
"github.com/rs/zerolog"
)
// Exec is a wrapper over exec.CommandContext. It does a couple of
@@ -23,7 +22,7 @@ import (
// 3. It moves the stderr into the return error, if needed.
//
// This is not suitable for high performance work -- it allocates new buffers each time.
func Exec(ctx context.Context, logger log.Logger, timeoutSeconds int, possibleBins []string, args []string, includeStderr bool) ([]byte, error) {
func Exec(ctx context.Context, log zerolog.Logger, timeoutSeconds int, possibleBins []string, args []string, includeStderr bool) ([]byte, error) {
ctx, cancel := context.WithTimeout(ctx, time.Duration(timeoutSeconds)*time.Second)
defer cancel()
@@ -42,10 +41,7 @@ func Exec(ctx context.Context, logger log.Logger, timeoutSeconds int, possibleBi
cmd.Stderr = &stderr
}
level.Debug(logger).Log(
"msg", "execing",
"cmd", cmd.String(),
)
log.Debug().Str("cmd", cmd.String()).Msg("execing")
switch err := cmd.Run(); {
case err == nil:
+3 -4
View File
@@ -8,14 +8,14 @@ import (
"context"
"testing"
"github.com/go-kit/log"
"github.com/rs/zerolog"
"github.com/stretchr/testify/assert"
)
func TestExec(t *testing.T) {
t.Parallel()
var tests = []struct {
tests := []struct {
name string
timeout int
bins []string
@@ -53,7 +53,7 @@ func TestExec(t *testing.T) {
}
ctx := context.Background()
logger := log.NewNopLogger()
logger := zerolog.Nop()
for _, tt := range tests {
tt := tt
@@ -71,7 +71,6 @@ func TestExec(t *testing.T) {
assert.NoError(t, err)
assert.Equal(t, []byte(tt.output), output)
}
})
}
}
+12 -15
View File
@@ -4,22 +4,21 @@ package tablehelpers
import (
"strings"
"github.com/go-kit/log"
"github.com/go-kit/log/level"
"github.com/osquery/osquery-go/plugin/table"
"github.com/rs/zerolog"
)
type constraintOptions struct {
allowedCharacters string
allowedValues []string
defaults []string
logger log.Logger
logger zerolog.Logger
}
type GetConstraintOpts func(*constraintOptions)
// WithLogger sets the logger to use
func WithLogger(logger log.Logger) GetConstraintOpts {
func WithLogger(logger zerolog.Logger) GetConstraintOpts {
return func(co *constraintOptions) {
co.logger = logger
}
@@ -50,7 +49,7 @@ func WithAllowedValues(allowed []string) GetConstraintOpts {
// a column. It's meant for the common, simple, usecase of iterating over them.
func GetConstraints(queryContext table.QueryContext, columnName string, opts ...GetConstraintOpts) []string {
co := &constraintOptions{
logger: log.NewNopLogger(),
logger: zerolog.Nop(),
}
for _, opt := range opts {
@@ -67,11 +66,10 @@ func GetConstraints(queryContext table.QueryContext, columnName string, opts ...
for _, c := range q.Constraints {
// No point in checking allowed characters, if we have an allowedValues. Just use it.
if len(co.allowedValues) == 0 && !co.OnlyAllowedCharacters(c.Expression) {
level.Info(co.logger).Log(
"msg", "Disallowed character in expression",
"column", columnName,
"expression", c.Expression,
)
co.logger.Info().
Str("column", columnName).
Str("expression", c.Expression).
Msg("Disallowed character in expression")
continue
}
@@ -85,11 +83,10 @@ func GetConstraints(queryContext table.QueryContext, columnName string, opts ...
}
if skip {
level.Info(co.logger).Log(
"msg", "Disallowed value in expression",
"column", columnName,
"expression", c.Expression,
)
co.logger.Info().
Str("column", columnName).
Str("expression", c.Expression).
Msg("Disallowed value in expression")
continue
}
}
@@ -15,9 +15,8 @@ import (
"github.com/fleetdm/fleet/v4/orbit/pkg/table/dataflattentable"
"github.com/fleetdm/fleet/v4/orbit/pkg/table/tablehelpers"
"github.com/fleetdm/fleet/v4/orbit/pkg/windows/windowsupdate"
"github.com/go-kit/log"
"github.com/go-kit/log/level"
"github.com/osquery/osquery-go/plugin/table"
"github.com/rs/zerolog"
"github.com/scjalliance/comshim"
)
@@ -29,20 +28,18 @@ const (
)
type Table struct {
logger log.Logger
logger zerolog.Logger
queryFunc queryFuncType
name string
}
func TablePlugin(mode tableMode, logger log.Logger) *table.Plugin {
func TablePlugin(mode tableMode, logger zerolog.Logger) *table.Plugin {
columns := dataflattentable.Columns(
table.TextColumn("locale"),
table.IntegerColumn("is_default"),
)
t := &Table{
logger: logger,
}
t := &Table{}
switch mode {
case UpdatesTable:
@@ -53,6 +50,8 @@ func TablePlugin(mode tableMode, logger log.Logger) *table.Plugin {
t.name = "windows_update_history"
}
t.logger = logger.With().Str("table", t.name).Logger()
return table.NewPlugin(t.name, columns, t.generate)
}
@@ -72,7 +71,7 @@ func (t *Table) generate(ctx context.Context, queryContext table.QueryContext) (
for _, locale := range tablehelpers.GetConstraints(queryContext, "locale", tablehelpers.WithDefaults("_default")) {
result, err := t.searchLocale(locale, queryContext)
if err != nil {
level.Info(t.logger).Log("msg", "got error searching", "locale", locale, "err", err)
t.logger.Info().Err(err).Str("locale", locale).Msg("got error searching")
continue
}
results = append(results, result...)
@@ -101,7 +100,7 @@ func (t *Table) searchLocale(locale string, queryContext table.QueryContext) ([]
for _, dataQuery := range tablehelpers.GetConstraints(queryContext, "query", tablehelpers.WithDefaults("*")) {
flatData, err := t.flattenOutput(dataQuery, searchResults)
if err != nil {
level.Info(t.logger).Log("msg", "flatten failed", "err", err)
t.logger.Err(err).Msg("flatten failed")
continue
}
@@ -10,7 +10,7 @@ import (
"time"
"github.com/fleetdm/fleet/v4/orbit/pkg/table/tablehelpers"
"github.com/go-kit/log"
"github.com/rs/zerolog"
"github.com/stretchr/testify/require"
)
@@ -31,14 +31,14 @@ func TestTable(t *testing.T) {
t.Parallel()
table := Table{
logger: log.NewNopLogger(),
logger: zerolog.Nop(),
queryFunc: tt.queryFunc,
}
ctx, cancel := context.WithTimeout(context.Background(), 45*time.Second)
defer cancel()
// ci doesn;t return data, but we can, at least, check that the underlying API doesn't error.
// ci doesn't return data, but we can, at least, check that the underlying API doesn't error.
_, err := table.generate(ctx, tablehelpers.MockQueryContext(nil))
require.NoError(t, err, "generate")
})