Skip to content

Commit

Permalink
Merge pull request #189 from yandex/dev
Browse files Browse the repository at this point in the history
v0.5.24
  • Loading branch information
oke11o authored May 13, 2024
2 parents 74a8145 + a926b55 commit 40ab59c
Show file tree
Hide file tree
Showing 41 changed files with 707 additions and 288 deletions.
9 changes: 9 additions & 0 deletions .changes/v0.5.24.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
## v0.5.24 - 2024-04-27
### Added
* HCL scenario: add support for "locals" block in hcl
* grpc/scenario: debug logs
* grpc generator: reflection metadata
### Changed
* discard_overflow default value =true
### Fixed
* http generator: fix answlog error
3 changes: 3 additions & 0 deletions .mapping.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
".changes/v0.5.21.md":"load/projects/pandora/.changes/v0.5.21.md",
".changes/v0.5.22.md":"load/projects/pandora/.changes/v0.5.22.md",
".changes/v0.5.23.md":"load/projects/pandora/.changes/v0.5.23.md",
".changes/v0.5.24.md":"load/projects/pandora/.changes/v0.5.24.md",
".changie.yaml":"load/projects/pandora/.changie.yaml",
".github/workflows/release.yml":"load/projects/pandora/.github/workflows/release.yml",
".github/workflows/test.yml":"load/projects/pandora/.github/workflows/test.yml",
Expand Down Expand Up @@ -257,6 +258,7 @@
"debian/source/format":"load/projects/pandora/debian/source/format",
"docs/eng/architecture.md":"load/projects/pandora/docs/eng/architecture.md",
"docs/eng/best-practices.md":"load/projects/pandora/docs/eng/best-practices.md",
"docs/eng/best_practices/discard-overflow.md":"load/projects/pandora/docs/eng/best_practices/discard-overflow.md",
"docs/eng/best_practices/rps-per-instance.md":"load/projects/pandora/docs/eng/best_practices/rps-per-instance.md",
"docs/eng/best_practices/shared-client.md":"load/projects/pandora/docs/eng/best_practices/shared-client.md",
"docs/eng/config.md":"load/projects/pandora/docs/eng/config.md",
Expand Down Expand Up @@ -286,6 +288,7 @@
"docs/rus/architecture.md":"load/projects/pandora/docs/rus/architecture.md",
"docs/rus/best-practices.md":"load/projects/pandora/docs/rus/best-practices.md",
"docs/rus/best_practices.md":"load/projects/pandora/docs/rus/best_practices.md",
"docs/rus/best_practices/discard-overflow.md":"load/projects/pandora/docs/rus/best_practices/discard-overflow.md",
"docs/rus/best_practices/rps-per-instance.md":"load/projects/pandora/docs/rus/best_practices/rps-per-instance.md",
"docs/rus/best_practices/shared-client.md":"load/projects/pandora/docs/rus/best_practices/shared-client.md",
"docs/rus/config.md":"load/projects/pandora/docs/rus/config.md",
Expand Down
10 changes: 10 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,16 @@ adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html),
and is generated by [Changie](https://github.com/miniscruff/changie).


## v0.5.24 - 2024-04-27
### Added
* HCL scenario: add support for "locals" block in hcl
* grpc/scenario: debug logs
* grpc generator: reflection metadata
### Changed
* discard_overflow default value =true
### Fixed
* http generator: fix answlog error

## v0.5.23 - 2024-04-16
### Added
* function for generate random values in scenario
Expand Down
12 changes: 11 additions & 1 deletion cli/cli.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ import (
"go.uber.org/zap/zapcore"
)

const Version = "0.5.23"
const Version = "0.5.24"
const defaultConfigFile = "load"
const stdinConfigSelector = "-"

Expand Down Expand Up @@ -218,6 +218,7 @@ func readConfig(args []string) *CliConfig {
}
}

log.Info("Pandora version", zap.String("version", Version))
if useStdinConfig {
v.SetConfigType("yaml")
configBuffer, err := ioutil.ReadAll(bufio.NewReader(os.Stdin))
Expand All @@ -235,6 +236,15 @@ func readConfig(args []string) *CliConfig {
log.Fatal("Config read failed", zap.Error(err))
}
}
pools := v.Get("pools").([]any)
for i, pool := range pools {
poolMap := pool.(map[string]any)
if _, ok := poolMap["discard_overflow"]; !ok {
poolMap["discard_overflow"] = true
}
pools[i] = poolMap
}
v.Set("pools", pools)

conf := DefaultConfig()
err = config.DecodeAndValidate(v.AllSettings(), conf)
Expand Down
38 changes: 23 additions & 15 deletions components/guns/grpc/core.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,13 +43,14 @@ type GrpcDialOptions struct {
}

type GunConfig struct {
Target string `validate:"required"`
ReflectPort int64 `config:"reflect_port"`
Timeout time.Duration `config:"timeout"` // grpc request timeout
TLS bool `config:"tls"`
DialOptions GrpcDialOptions `config:"dial_options"`
AnswLog AnswLogConfig `config:"answlog"`
SharedClient struct {
Target string `validate:"required"`
ReflectPort int64 `config:"reflect_port"`
ReflectMetadata metadata.MD `config:"reflect_metadata"`
Timeout time.Duration `config:"timeout"` // grpc request timeout
TLS bool `config:"tls"`
DialOptions GrpcDialOptions `config:"dial_options"`
AnswLog AnswLogConfig `config:"answlog"`
SharedClient struct {
ClientNumber int `config:"client-number,omitempty"`
Enabled bool `config:"enabled"`
} `config:"shared-client,omitempty"`
Expand Down Expand Up @@ -110,8 +111,7 @@ func (g *Gun) prepareMethodList(opts *warmup.Options) (map[string]desc.MethodDes
}
defer conn.Close()

meta := make(metadata.MD)
refCtx := metadata.NewOutgoingContext(context.Background(), meta)
refCtx := metadata.NewOutgoingContext(context.Background(), g.Conf.ReflectMetadata)
refClient := grpcreflect.NewClientAuto(refCtx, conn)
listServices, err := refClient.ListServices()
if err != nil {
Expand Down Expand Up @@ -238,27 +238,35 @@ func (g *Gun) shoot(ammo *ammo.Ammo) {
g.GunDeps.Log.Error("response error", zap.Error(err))
}

g.Answ(&method, message, ammo.Metadata, out, grpcErr, code)
}

func (g *Gun) Answ(method *desc.MethodDescriptor, message *dynamic.Message, metadata map[string]string, out proto.Message, grpcErr error, code int) {
if g.Conf.AnswLog.Enabled {
switch g.Conf.AnswLog.Filter {
case "all":
g.AnswLogging(g.AnswLog, &method, message, out, grpcErr)
g.AnswLogging(g.AnswLog, method, message, metadata, out, grpcErr)

case "warning":
if code >= 400 {
g.AnswLogging(g.AnswLog, &method, message, out, grpcErr)
g.AnswLogging(g.AnswLog, method, message, metadata, out, grpcErr)
}

case "error":
if code >= 500 {
g.AnswLogging(g.AnswLog, &method, message, out, grpcErr)
g.AnswLogging(g.AnswLog, method, message, metadata, out, grpcErr)
}
}
}
}

func (g *Gun) AnswLogging(logger *zap.Logger, method *desc.MethodDescriptor, request proto.Message, response proto.Message, grpcErr error) {
logger.Debug("Request:", zap.Stringer("method", method), zap.Stringer("message", request))
logger.Debug("Response:", zap.Stringer("resp", response), zap.Error(grpcErr))
func (g *Gun) AnswLogging(logger *zap.Logger, method *desc.MethodDescriptor, request proto.Message, metadata map[string]string, response proto.Message, grpcErr error) {
logger.Debug("Request:", zap.Stringer("method", method), zap.Stringer("message", request), zap.Any("metadata", metadata))
if response != nil {
logger.Debug("Response:", zap.Stringer("resp", response), zap.Error(grpcErr))
} else {
logger.Debug("Response:", zap.String("resp", "empty"), zap.Error(grpcErr))
}
}

func (g *Gun) makeConnect() (conn *grpc.ClientConn, err error) {
Expand Down
44 changes: 17 additions & 27 deletions components/guns/grpc/scenario/core.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,13 @@ import (
const defaultTimeout = time.Second * 15

type GunConfig struct {
Target string `validate:"required"`
ReflectPort int64 `config:"reflect_port"`
Timeout time.Duration `config:"timeout"` // grpc request timeout
TLS bool `config:"tls"`
DialOptions GrpcDialOptions `config:"dial_options"`
AnswLog AnswLogConfig `config:"answlog"`
Target string `validate:"required"`
ReflectPort int64 `config:"reflect_port"`
ReflectMetadata metadata.MD `config:"reflect_metadata"`
Timeout time.Duration `config:"timeout"` // grpc request timeout
TLS bool `config:"tls"`
DialOptions GrpcDialOptions `config:"dial_options"`
AnswLog AnswLogConfig `config:"answlog"`
}

type GrpcDialOptions struct {
Expand Down Expand Up @@ -57,10 +58,11 @@ func NewGun(conf GunConfig) *Gun {
return &Gun{
templ: NewTextTemplater(),
gun: &grpcgun.Gun{Conf: grpcgun.GunConfig{
Target: conf.Target,
ReflectPort: conf.ReflectPort,
Timeout: conf.Timeout,
TLS: conf.TLS,
Target: conf.Target,
ReflectPort: conf.ReflectPort,
ReflectMetadata: conf.ReflectMetadata,
Timeout: conf.Timeout,
TLS: conf.TLS,
DialOptions: grpcgun.GrpcDialOptions{
Authority: conf.DialOptions.Authority,
Timeout: conf.DialOptions.Timeout,
Expand Down Expand Up @@ -116,6 +118,9 @@ func (g *Gun) shoot(ammo *Scenario, templateVars map[string]any) error {

requestVars := map[string]any{}
templateVars["request"] = requestVars
if g.gun.DebugLog {
g.gun.GunDeps.Log.Debug("Source variables", zap.Any("variables", templateVars))
}

startAt := time.Now()
for _, call := range ammo.Calls {
Expand Down Expand Up @@ -154,7 +159,7 @@ func (g *Gun) shootStep(step *Call, sample *netsample.Sample, ammoName string, t
}
preprocVars = mergeMaps(preprocVars, pp)
if g.gun.DebugLog {
g.gun.GunDeps.Log.Debug("PreparePreprocessor variables", zap.Any(fmt.Sprintf(".resuest.%s.preprocessor", step.Name), pp))
g.gun.GunDeps.Log.Debug("PreparePreprocessor variables", zap.Any(fmt.Sprintf(".request.%s.preprocessor", step.Name), pp))
}
}
stepVars["preprocessor"] = preprocVars
Expand Down Expand Up @@ -198,22 +203,7 @@ func (g *Gun) shootStep(step *Call, sample *netsample.Sample, ammoName string, t
g.gun.GunDeps.Log.Error("response error", zap.Error(err))
}

if g.gun.Conf.AnswLog.Enabled {
switch g.gun.Conf.AnswLog.Filter {
case "all":
g.gun.AnswLogging(g.gun.AnswLog, &method, message, out, grpcErr)

case "warning":
if code >= 400 {
g.gun.AnswLogging(g.gun.AnswLog, &method, message, out, grpcErr)
}

case "error":
if code >= 500 {
g.gun.AnswLogging(g.gun.AnswLog, &method, message, out, grpcErr)
}
}
}
g.gun.Answ(&method, message, step.Metadata, out, grpcErr, code)

for _, postProcessor := range step.Postprocessors {
pp, err := postProcessor.Process(out, code)
Expand Down
46 changes: 14 additions & 32 deletions components/guns/http/base.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,16 +25,6 @@ const (
EmptyTag = "__EMPTY__"
)

type BaseGunConfig struct {
AutoTag AutoTagConfig `config:"auto-tag"`
AnswLog AnswLogConfig `config:"answlog"`
HTTPTrace HTTPTraceConfig `config:"httptrace"`
SharedClient struct {
ClientNumber int `config:"client-number,omitempty"`
Enabled bool `config:"enabled"`
} `config:"shared-client,omitempty"`
}

// AutoTagConfig configure automatic tags generation based on ammo URI. First AutoTag URI path elements becomes tag.
// Example: /my/very/deep/page?id=23&param=33 -> /my/very when uri-elements: 2.
type AutoTagConfig struct {
Expand All @@ -54,29 +44,10 @@ type HTTPTraceConfig struct {
TraceEnabled bool `config:"trace"`
}

func DefaultBaseGunConfig() BaseGunConfig {
return BaseGunConfig{
AutoTag: AutoTagConfig{
Enabled: false,
URIElements: 2,
NoTagOnly: true,
},
AnswLog: AnswLogConfig{
Enabled: false,
Path: "answ.log",
Filter: "error",
},
HTTPTrace: HTTPTraceConfig{
DumpEnabled: false,
TraceEnabled: false,
},
}
}

func NewBaseGun(clientConstructor ClientConstructor, cfg HTTPGunConfig, answLog *zap.Logger) *BaseGun {
func NewBaseGun(clientConstructor ClientConstructor, cfg GunConfig, answLog *zap.Logger) *BaseGun {
client := clientConstructor(cfg.Client, cfg.Target)
return &BaseGun{
Config: cfg.Base,
Config: cfg,
OnClose: func() error {
client.CloseIdleConnections()
return nil
Expand All @@ -91,7 +62,7 @@ func NewBaseGun(clientConstructor ClientConstructor, cfg HTTPGunConfig, answLog

type BaseGun struct {
DebugLog bool // Automaticaly set in Bind if Log accepts debug messages.
Config BaseGunConfig
Config GunConfig
Connect func(ctx context.Context) error // Optional hook.
OnClose func() error // Optional. Called on Close().
Aggregator netsample.Aggregator // Lazy set via BindResultTo.
Expand Down Expand Up @@ -183,6 +154,17 @@ func (b *BaseGun) Shoot(ammo Ammo) {
b.Log.Warn("Invalid ammo", zap.Uint64("request", ammo.ID()))
return
}

if b.Config.SSL {
req.URL.Scheme = "https"
} else {
req.URL.Scheme = "http"
}
if req.Host == "" {
req.Host = getHostWithoutPort(b.Config.Target)
}
req.URL.Host = b.Config.TargetResolved

if b.DebugLog {
b.Log.Debug("Prepared ammo to shoot", zap.Stringer("url", req.URL))
}
Expand Down
5 changes: 3 additions & 2 deletions components/guns/http/base_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ func (s *BaseGunSuite) SetupSuite() {
}

func (s *BaseGunSuite) SetupTest() {
s.base = BaseGun{Config: DefaultBaseGunConfig()}
s.base = BaseGun{Config: DefaultHTTPGunConfig()}
}

func (s *BaseGunSuite) Test_BindResultTo_Panics() {
Expand Down Expand Up @@ -335,8 +335,9 @@ func Test_Autotag(t *testing.T) {
}

func Test_ConfigDecode(t *testing.T) {
var conf BaseGunConfig
var conf GunConfig
coretest.DecodeAndValidateT(t, `
target: localhost:80
auto-tag:
enabled: true
uri-elements: 3
Expand Down
37 changes: 0 additions & 37 deletions components/guns/http/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -173,43 +173,6 @@ func (c *panicOnHTTP1Client) Do(req *http.Request) (*http.Response, error) {
return res, nil
}

func WrapClientHostResolving(client Client, cfg HTTPGunConfig, targetResolved string) Client {
hostname := getHostWithoutPort(cfg.Target)
scheme := "http"
if cfg.SSL {
scheme = "https"
}
return &httpDecoratedClient{
client: client,
scheme: scheme,
hostname: hostname,
targetResolved: targetResolved,
}
}

type httpDecoratedClient struct {
client Client
scheme string
hostname string
targetResolved string
}

func (c *httpDecoratedClient) Do(req *http.Request) (*http.Response, error) {
if req.Host == "" {
req.Host = c.hostname
}

if c.targetResolved != "" {
req.URL.Host = c.targetResolved
}
req.URL.Scheme = c.scheme
return c.client.Do(req)
}

func (c *httpDecoratedClient) CloseIdleConnections() {
c.client.CloseIdleConnections()
}

func checkHTTP2(state *tls.ConnectionState) error {
if state == nil {
return errors.New("http2: non TLS connection")
Expand Down
Loading

0 comments on commit 40ab59c

Please sign in to comment.