-
Notifications
You must be signed in to change notification settings - Fork 4.9k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Browse files
Browse the repository at this point in the history
* support for TIME_NOW var * fix import ordering * add documentation * add unit tests * fix linting error * path is a date time formatter * fmt * remove unneeded * update docs * add UTC * improve message * change link * create new Unpacker * fmt * description of the use case * unit tests (cherry picked from commit e067577) Co-authored-by: Yoel Spotts <[email protected]> Co-authored-by: Craig MacKenzie <[email protected]>
- Loading branch information
1 parent
2b50d68
commit 26aad5d
Showing
6 changed files
with
290 additions
and
16 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,100 @@ | ||
// Licensed to Elasticsearch B.V. under one or more contributor | ||
// license agreements. See the NOTICE file distributed with | ||
// this work for additional information regarding copyright | ||
// ownership. Elasticsearch B.V. licenses this file to you under | ||
// the Apache License, Version 2.0 (the "License"); you may | ||
// not use this file except in compliance with the License. | ||
// You may obtain a copy of the License at | ||
// | ||
// http://www.apache.org/licenses/LICENSE-2.0 | ||
// | ||
// Unless required by applicable law or agreed to in writing, | ||
// software distributed under the License is distributed on an | ||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY | ||
// KIND, either express or implied. See the License for the | ||
// specific language governing permissions and limitations | ||
// under the License. | ||
|
||
package fileout | ||
|
||
import ( | ||
"testing" | ||
"time" | ||
|
||
"github.com/stretchr/testify/assert" | ||
|
||
"github.com/elastic/elastic-agent-libs/config" | ||
"github.com/elastic/elastic-agent-libs/mapstr" | ||
) | ||
|
||
func TestConfig(t *testing.T) { | ||
for name, test := range map[string]struct { | ||
config *config.C | ||
useWindowsPath bool | ||
assertion func(t *testing.T, config *fileOutConfig, err error) | ||
}{ | ||
"default config": { | ||
config: config.MustNewConfigFrom([]byte(`{ }`)), | ||
assertion: func(t *testing.T, actual *fileOutConfig, err error) { | ||
expectedConfig := &fileOutConfig{ | ||
NumberOfFiles: 7, | ||
RotateEveryKb: 10 * 1024, | ||
Permissions: 0600, | ||
RotateOnStartup: true, | ||
} | ||
|
||
assert.Equal(t, expectedConfig, actual) | ||
assert.Nil(t, err) | ||
}, | ||
}, | ||
"config given with posix path": { | ||
config: config.MustNewConfigFrom(mapstr.M{ | ||
"number_of_files": 10, | ||
"rotate_every_kb": 5 * 1024, | ||
"path": "/tmp/packetbeat/%{+yyyy-MM-dd-mm-ss-SSSSSS}", | ||
"filename": "pb", | ||
}), | ||
assertion: func(t *testing.T, actual *fileOutConfig, err error) { | ||
assert.Equal(t, uint(10), actual.NumberOfFiles) | ||
assert.Equal(t, uint(5*1024), actual.RotateEveryKb) | ||
assert.Equal(t, true, actual.RotateOnStartup) | ||
assert.Equal(t, uint32(0600), actual.Permissions) | ||
assert.Equal(t, "pb", actual.Filename) | ||
|
||
path, runErr := actual.Path.Run(time.Date(2024, 1, 2, 3, 4, 5, 67890, time.UTC)) | ||
assert.Nil(t, runErr) | ||
|
||
assert.Equal(t, "/tmp/packetbeat/2024-01-02-04-05-000067", path) | ||
assert.Nil(t, err) | ||
}, | ||
}, | ||
"config given with windows path": { | ||
useWindowsPath: true, | ||
config: config.MustNewConfigFrom(mapstr.M{ | ||
"number_of_files": 10, | ||
"rotate_every_kb": 5 * 1024, | ||
"path": "c:\\tmp\\packetbeat\\%{+yyyy-MM-dd-mm-ss-SSSSSS}", | ||
"filename": "pb", | ||
}), | ||
assertion: func(t *testing.T, actual *fileOutConfig, err error) { | ||
assert.Equal(t, uint(10), actual.NumberOfFiles) | ||
assert.Equal(t, uint(5*1024), actual.RotateEveryKb) | ||
assert.Equal(t, true, actual.RotateOnStartup) | ||
assert.Equal(t, uint32(0600), actual.Permissions) | ||
assert.Equal(t, "pb", actual.Filename) | ||
|
||
path, runErr := actual.Path.Run(time.Date(2024, 1, 2, 3, 4, 5, 67890, time.UTC)) | ||
assert.Nil(t, runErr) | ||
|
||
assert.Equal(t, "c:\\tmp\\packetbeat\\2024-01-02-04-05-000067", path) | ||
assert.Nil(t, err) | ||
}, | ||
}, | ||
} { | ||
t.Run(name, func(t *testing.T) { | ||
isWindowsPath = test.useWindowsPath | ||
cfg, err := readConfig(test.config) | ||
test.assertion(t, cfg, err) | ||
}) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
// Licensed to Elasticsearch B.V. under one or more contributor | ||
// license agreements. See the NOTICE file distributed with | ||
// this work for additional information regarding copyright | ||
// ownership. Elasticsearch B.V. licenses this file to you under | ||
// the Apache License, Version 2.0 (the "License"); you may | ||
// not use this file except in compliance with the License. | ||
// You may obtain a copy of the License at | ||
// | ||
// http://www.apache.org/licenses/LICENSE-2.0 | ||
// | ||
// Unless required by applicable law or agreed to in writing, | ||
// software distributed under the License is distributed on an | ||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY | ||
// KIND, either express or implied. See the License for the | ||
// specific language governing permissions and limitations | ||
// under the License. | ||
|
||
package fileout | ||
|
||
import ( | ||
"os" | ||
"strings" | ||
"time" | ||
|
||
"github.com/elastic/beats/v7/libbeat/common/fmtstr" | ||
|
||
"github.com/elastic/beats/v7/libbeat/beat" | ||
) | ||
|
||
var isWindowsPath = os.PathSeparator == '\\' | ||
|
||
// PathFormatString is a wrapper around EventFormatString for the | ||
// handling paths with a format expression that has access to the timestamp format. | ||
// It has special handling for paths, specifically for windows path separator | ||
// which would be interpreted as an escape character. This formatter double escapes | ||
// the path separator so it is properly interpreted by the fmtstr processor | ||
type PathFormatString struct { | ||
efs *fmtstr.EventFormatString | ||
} | ||
|
||
// Run executes the format string returning a new expanded string or an error | ||
// if execution or event field expansion fails. | ||
func (fs *PathFormatString) Run(timestamp time.Time) (string, error) { | ||
placeholderEvent := &beat.Event{ | ||
Timestamp: timestamp, | ||
} | ||
return fs.efs.Run(placeholderEvent) | ||
} | ||
|
||
// Unpack tries to initialize the PathFormatString from provided value | ||
// (which must be a string). Unpack method satisfies go-ucfg.Unpacker interface | ||
// required by config.C, in order to use PathFormatString with | ||
// `common.(*Config).Unpack()`. | ||
func (fs *PathFormatString) Unpack(v interface{}) error { | ||
path, ok := v.(string) | ||
if !ok { | ||
return nil | ||
} | ||
|
||
if isWindowsPath { | ||
path = strings.ReplaceAll(path, "\\", "\\\\") | ||
} | ||
|
||
fs.efs = &fmtstr.EventFormatString{} | ||
return fs.efs.Unpack(path) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,87 @@ | ||
// Licensed to Elasticsearch B.V. under one or more contributor | ||
// license agreements. See the NOTICE file distributed with | ||
// this work for additional information regarding copyright | ||
// ownership. Elasticsearch B.V. licenses this file to you under | ||
// the Apache License, Version 2.0 (the "License"); you may | ||
// not use this file except in compliance with the License. | ||
// You may obtain a copy of the License at | ||
// | ||
// http://www.apache.org/licenses/LICENSE-2.0 | ||
// | ||
// Unless required by applicable law or agreed to in writing, | ||
// software distributed under the License is distributed on an | ||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY | ||
// KIND, either express or implied. See the License for the | ||
// specific language governing permissions and limitations | ||
// under the License. | ||
|
||
package fileout | ||
|
||
import ( | ||
"testing" | ||
"time" | ||
|
||
"github.com/stretchr/testify/assert" | ||
) | ||
|
||
func TestPathFormatString(t *testing.T) { | ||
tests := []struct { | ||
title string | ||
useWindowsPath bool | ||
format string | ||
timestamp time.Time | ||
expected string | ||
}{ | ||
{ | ||
"empty string", | ||
false, | ||
"", | ||
time.Time{}, | ||
"", | ||
}, | ||
{ | ||
"no fields configured", | ||
false, | ||
"format string", | ||
time.Time{}, | ||
"format string", | ||
}, | ||
{ | ||
"test timestamp formatter", | ||
false, | ||
"timestamp: %{+YYYY.MM.dd}", | ||
time.Date(2015, 5, 1, 20, 12, 34, 0, time.UTC), | ||
"timestamp: 2015.05.01", | ||
}, | ||
{ | ||
"test timestamp formatter with posix path", | ||
false, | ||
"/tmp/%{+YYYY.MM.dd}", | ||
time.Date(2015, 5, 1, 20, 12, 34, 0, time.UTC), | ||
"/tmp/2015.05.01", | ||
}, | ||
{ | ||
"test timestamp formatter with windows path", | ||
true, | ||
"C:\\tmp\\%{+YYYY.MM.dd}", | ||
time.Date(2015, 5, 1, 20, 12, 34, 0, time.UTC), | ||
"C:\\tmp\\2015.05.01", | ||
}, | ||
} | ||
|
||
for i, test := range tests { | ||
t.Logf("test(%v): %v", i, test.title) | ||
isWindowsPath = test.useWindowsPath | ||
pfs := &PathFormatString{} | ||
err := pfs.Unpack(test.format) | ||
if err != nil { | ||
t.Error(err) | ||
continue | ||
} | ||
|
||
actual, err := pfs.Run(test.timestamp) | ||
|
||
assert.NoError(t, err) | ||
assert.Equal(t, test.expected, actual) | ||
} | ||
} |