-
Notifications
You must be signed in to change notification settings - Fork 66
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #97 from yandex/feature/85
Custom pandora example
- Loading branch information
Showing
12 changed files
with
251 additions
and
21 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
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 |
---|---|---|
|
@@ -3,34 +3,36 @@ | |
// license that can be found in the LICENSE file. | ||
// Author: Vladimir Skipor <[email protected]> | ||
|
||
package core | ||
package coreimport | ||
|
||
import ( | ||
"reflect" | ||
|
||
"github.com/spf13/afero" | ||
"github.com/yandex/pandora/core/aggregator" | ||
"github.com/yandex/pandora/core/datasink" | ||
"github.com/yandex/pandora/lib/tag" | ||
"go.uber.org/zap" | ||
|
||
"github.com/yandex/pandora/core" | ||
"github.com/yandex/pandora/core/aggregator" | ||
"github.com/yandex/pandora/core/aggregator/netsample" | ||
"github.com/yandex/pandora/core/config" | ||
"github.com/yandex/pandora/core/datasink" | ||
"github.com/yandex/pandora/core/datasource" | ||
"github.com/yandex/pandora/core/plugin" | ||
"github.com/yandex/pandora/core/plugin/pluginconfig" | ||
"github.com/yandex/pandora/core/provider" | ||
"github.com/yandex/pandora/core/register" | ||
"github.com/yandex/pandora/core/schedule" | ||
"github.com/yandex/pandora/lib/tag" | ||
) | ||
|
||
const ( | ||
fileSinkKey = "file" | ||
fileDataKey = "file" | ||
compositeScheduleKey = "composite" | ||
) | ||
|
||
func Import(fs afero.Fs) { | ||
|
||
register.DataSink(fileSinkKey, func(conf datasink.FileConfig) core.DataSink { | ||
register.DataSink(fileDataKey, func(conf datasink.FileConfig) core.DataSink { | ||
return datasink.NewFile(fs, conf) | ||
}) | ||
const ( | ||
|
@@ -48,11 +50,31 @@ func Import(fs afero.Fs) { | |
return | ||
}) | ||
|
||
register.DataSource(fileDataKey, func(conf datasource.FileConfig) core.DataSource { | ||
return datasource.NewFile(fs, conf) | ||
}) | ||
const ( | ||
stdinSourceKey = "stdin" | ||
) | ||
register.DataSource(stdinSourceKey, datasource.NewStdin) | ||
AddSinkConfigHook(func(str string) (ok bool, pluginType string, _ map[string]interface{}) { | ||
if str != stdinSourceKey { | ||
return | ||
} | ||
return true, stdinSourceKey, nil | ||
}) | ||
register.DataSource("inline", datasource.NewInline) | ||
|
||
// NOTE(skipor): json provider SHOULD NOT used normally. Register your own, that will return | ||
// type that you need, but untyped map. | ||
RegisterCustomJSONProvider("json", func() core.Ammo { return map[string]interface{}{} }) | ||
|
||
register.Aggregator("phout", func(conf netsample.PhoutConfig) (core.Aggregator, error) { | ||
a, err := netsample.NewPhout(fs, conf) | ||
return netsample.WrapAggregator(a), err | ||
}) | ||
register.Aggregator("jsonlines", aggregator.NewJSONLinesAggregator, aggregator.DefaultJSONLinesAggregatorConfig) | ||
register.Aggregator("json", aggregator.NewJSONLinesAggregator, aggregator.DefaultJSONLinesAggregatorConfig) // TODO(skipor): should be done via alias, but we don't have them yet | ||
register.Aggregator("log", aggregator.NewLog) | ||
register.Aggregator("discard", aggregator.NewDiscard) | ||
|
||
|
@@ -86,13 +108,70 @@ func isPluginOrFactory(expectedPluginType, actualType reflect.Type) bool { | |
type PluginConfigStringHook func(str string) (ok bool, pluginType string, conf map[string]interface{}) | ||
|
||
var ( | ||
dataSinkConfigHooks []PluginConfigStringHook | ||
dataSinkConfigHooks []PluginConfigStringHook | ||
dataSourceConfigHooks []PluginConfigStringHook | ||
) | ||
|
||
func AddSinkConfigHook(hook PluginConfigStringHook) { | ||
dataSinkConfigHooks = append(dataSinkConfigHooks, hook) | ||
} | ||
|
||
func AddSourceConfigHook(hook PluginConfigStringHook) { | ||
dataSourceConfigHooks = append(dataSourceConfigHooks, hook) | ||
} | ||
|
||
func RegisterCustomJSONProvider(name string, newAmmo func() core.Ammo) { | ||
register.Provider(name, func(conf provider.JSONProviderConfig) core.Provider { | ||
return provider.NewJSONProvider(newAmmo, conf) | ||
}, provider.DefaultJSONProviderConfig) | ||
} | ||
|
||
// sourceStringHook helps to decode string as core.DataSource plugin. | ||
// Try use source hooks and use file as fallback. | ||
func sourceStringHook(f reflect.Type, t reflect.Type, data interface{}) (interface{}, error) { | ||
if f.Kind() != reflect.String { | ||
return data, nil | ||
} | ||
if !isPluginOrFactory(dataSourceType, t) { | ||
return data, nil | ||
} | ||
if tag.Debug { | ||
zap.L().Debug("DataSource string hook triggered") | ||
} | ||
var ( | ||
ok bool | ||
pluginType string | ||
conf map[string]interface{} | ||
) | ||
dataStr := data.(string) | ||
|
||
for _, hook := range dataSourceConfigHooks { | ||
ok, pluginType, conf = hook(dataStr) | ||
zap.L().Debug("Source hooked", zap.String("plugin", pluginType)) | ||
if ok { | ||
break | ||
} | ||
} | ||
|
||
if !ok { | ||
zap.L().Debug("Consider source as a file", zap.String("source", dataStr)) | ||
pluginType = fileDataKey | ||
conf = map[string]interface{}{ | ||
"path": data, | ||
} | ||
} | ||
|
||
if conf == nil { | ||
conf = make(map[string]interface{}) | ||
} | ||
conf[pluginconfig.PluginNameKey] = pluginType | ||
|
||
if tag.Debug { | ||
zap.L().Debug("Hooked DataSource config", zap.Any("config", conf)) | ||
} | ||
return conf, nil | ||
} | ||
|
||
// sinkStringHook helps to decode string as core.DataSink plugin. | ||
// Try use sink hooks and use file as fallback. | ||
func sinkStringHook(f reflect.Type, t reflect.Type, data interface{}) (interface{}, error) { | ||
|
@@ -114,13 +193,15 @@ func sinkStringHook(f reflect.Type, t reflect.Type, data interface{}) (interface | |
|
||
for _, hook := range dataSinkConfigHooks { | ||
ok, pluginType, conf = hook(dataStr) | ||
zap.L().Debug("Sink hooked", zap.String("plugin", pluginType)) | ||
if ok { | ||
break | ||
} | ||
} | ||
|
||
if !ok { | ||
pluginType = fileSinkKey | ||
zap.L().Debug("Consider sink as a file", zap.String("source", dataStr)) | ||
pluginType = fileDataKey | ||
conf = map[string]interface{}{ | ||
"path": data, | ||
} | ||
|
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
File renamed without changes.
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,27 @@ | ||
pools: | ||
- gun: | ||
type: my-custom-gun-name | ||
target: example.com:80 | ||
|
||
ammo: | ||
type: my-custom-provider-name | ||
source: # You may just write file path here. Or stdin. | ||
type: inline | ||
data: | | ||
{"url": "url1", "queryParam": "query1"} | ||
{"url": "url2", "queryParam": "query2"} | ||
result: | ||
type: json | ||
sink: stdout # Just for interactivity print result to stdout. Usually file used here. | ||
|
||
rps: | ||
- {duration: 2s, type: line, from: 1, to: 5} | ||
- {duration: 3s, type: const, ops: 5} | ||
- {duration: 2s, type: line, from: 5, to: 1} | ||
startup: | ||
type: once | ||
times: 5 | ||
|
||
log: | ||
level: debug |
Oops, something went wrong.