mirror of
https://github.com/aykhans/sarin.git
synced 2026-08-31 12:15:09 +00:00
feat(logging): add runtime log levels, response logging, and progress/log-file controls
- --log-level (comma-separated string: info, error): pick which logs are emitted; the level set is resolved once, up front - Log responses at the info level: full self-contained JSON to a file or stderr, a compact "status duration | body" summary in the TUI log box - Route logs independently of the progress display: the TUI log box when it runs, stderr when piped, or a file via --log-file/-w (parent dir validated up front) - Replace --quiet with --progress (bar | none, default bar): progress and logs are now independent — progress=none still shows the log box; quiet == progress=none with an empty log level - Rename the internal "message" concept to "log" (runtimeLog, runtimeLogger, ...)
This commit is contained in:
+22
-7
@@ -27,7 +27,9 @@ Flags:
|
||||
-c, -concurrency uint Number of concurrent requests (default %d)
|
||||
-r, -requests uint Number of total requests
|
||||
-d, -duration time Maximum duration for the test (e.g. 30s, 1m, 5h)
|
||||
-q, -quiet bool Hide the progress bar and runtime logs (default %v)
|
||||
-l, -log-level string Runtime log levels to emit, comma-separated (possible values: info, error) (default %s)
|
||||
-w, -log-file string Write runtime logs to this file instead of the terminal/stderr
|
||||
-p, -progress string Progress display (possible values: bar, none) (default '%v')
|
||||
-o, -output string Output format (possible values: table, json, yaml, none) (default '%v')
|
||||
-z, -dry-run bool Run without sending requests (default %v)
|
||||
|
||||
@@ -88,7 +90,9 @@ func (parser ConfigCLIParser) Parse() (*Config, error) {
|
||||
concurrency uint
|
||||
requestCount uint64
|
||||
duration time.Duration
|
||||
quiet bool
|
||||
logLevel string
|
||||
logFile string
|
||||
progress string
|
||||
output string
|
||||
dryRun bool
|
||||
|
||||
@@ -127,8 +131,14 @@ func (parser ConfigCLIParser) Parse() (*Config, error) {
|
||||
flagSet.DurationVar(&duration, "duration", 0, "Maximum duration for the test")
|
||||
flagSet.DurationVar(&duration, "d", 0, "Maximum duration for the test")
|
||||
|
||||
flagSet.BoolVar(&quiet, "quiet", false, "Hide the progress bar and runtime logs")
|
||||
flagSet.BoolVar(&quiet, "q", false, "Hide the progress bar and runtime logs")
|
||||
flagSet.StringVar(&logLevel, "log-level", "", "Runtime log levels to emit, comma-separated (possible values: info, error)")
|
||||
flagSet.StringVar(&logLevel, "l", "", "Runtime log levels to emit, comma-separated (possible values: info, error)")
|
||||
|
||||
flagSet.StringVar(&logFile, "log-file", "", "Write runtime logs to this file instead of the terminal/stderr")
|
||||
flagSet.StringVar(&logFile, "w", "", "Write runtime logs to this file instead of the terminal/stderr")
|
||||
|
||||
flagSet.StringVar(&progress, "progress", "", "Progress display (possible values: bar, none)")
|
||||
flagSet.StringVar(&progress, "p", "", "Progress display (possible values: bar, none)")
|
||||
|
||||
flagSet.StringVar(&output, "output", "", "Output format (possible values: table, json, yaml, none)")
|
||||
flagSet.StringVar(&output, "o", "", "Output format (possible values: table, json, yaml, none)")
|
||||
@@ -205,8 +215,12 @@ func (parser ConfigCLIParser) Parse() (*Config, error) {
|
||||
config.Requests = new(requestCount)
|
||||
case "duration", "d":
|
||||
config.Duration = new(duration)
|
||||
case "quiet", "q":
|
||||
config.Quiet = new(quiet)
|
||||
case "log-level", "l":
|
||||
config.LogLevel = new(logLevel)
|
||||
case "log-file", "w":
|
||||
config.LogFile = new(logFile)
|
||||
case "progress", "p":
|
||||
config.Progress = new(ConfigProgressType(progress))
|
||||
case "output", "o":
|
||||
config.Output = new(ConfigOutputType(output))
|
||||
case "dry-run", "z":
|
||||
@@ -265,7 +279,8 @@ func (parser ConfigCLIParser) PrintHelp() {
|
||||
cliUsageText+"\n",
|
||||
Defaults.ShowConfig,
|
||||
Defaults.Concurrency,
|
||||
Defaults.Quiet,
|
||||
Defaults.LogLevel,
|
||||
Defaults.Progress,
|
||||
Defaults.Output,
|
||||
Defaults.DryRun,
|
||||
|
||||
|
||||
+108
-30
@@ -6,6 +6,7 @@ import (
|
||||
"fmt"
|
||||
"net/url"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"slices"
|
||||
"strconv"
|
||||
"strings"
|
||||
@@ -17,6 +18,7 @@ import (
|
||||
"github.com/charmbracelet/glamour/styles"
|
||||
"github.com/charmbracelet/lipgloss"
|
||||
"github.com/charmbracelet/x/term"
|
||||
"go.aykhans.me/sarin/internal/sarin"
|
||||
"go.aykhans.me/sarin/internal/script"
|
||||
"go.aykhans.me/sarin/internal/types"
|
||||
"go.aykhans.me/sarin/internal/version"
|
||||
@@ -31,25 +33,28 @@ var Defaults = struct {
|
||||
RequestTimeout time.Duration
|
||||
Concurrency uint
|
||||
ShowConfig bool
|
||||
Quiet bool
|
||||
Progress ConfigProgressType
|
||||
Insecure bool
|
||||
Output ConfigOutputType
|
||||
DryRun bool
|
||||
LogLevel string
|
||||
}{
|
||||
UserAgent: "Sarin/" + version.Version,
|
||||
Method: "GET",
|
||||
RequestTimeout: time.Second * 10,
|
||||
Concurrency: 1,
|
||||
ShowConfig: false,
|
||||
Quiet: false,
|
||||
Progress: ConfigProgressTypeBar,
|
||||
Insecure: false,
|
||||
Output: ConfigOutputTypeTable,
|
||||
DryRun: false,
|
||||
LogLevel: "error",
|
||||
}
|
||||
|
||||
var (
|
||||
ValidProxySchemes = []string{"http", "https", "socks5", "socks5h"}
|
||||
ValidRequestURLSchemes = []string{"http", "https"}
|
||||
ValidLogLevels = []string{"info", "error"}
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -70,27 +75,36 @@ var (
|
||||
ConfigOutputTypeNone ConfigOutputType = "none"
|
||||
)
|
||||
|
||||
type ConfigProgressType string
|
||||
|
||||
var (
|
||||
ConfigProgressTypeBar ConfigProgressType = "bar"
|
||||
ConfigProgressTypeNone ConfigProgressType = "none"
|
||||
)
|
||||
|
||||
type Config struct {
|
||||
ShowConfig *bool `yaml:"showConfig,omitempty"`
|
||||
Files []types.ConfigFile `yaml:"files,omitempty"`
|
||||
Methods []string `yaml:"methods,omitempty"`
|
||||
URL *url.URL `yaml:"url,omitempty"`
|
||||
Timeout *time.Duration `yaml:"timeout,omitempty"`
|
||||
Concurrency *uint `yaml:"concurrency,omitempty"`
|
||||
Requests *uint64 `yaml:"requests,omitempty"`
|
||||
Duration *time.Duration `yaml:"duration,omitempty"`
|
||||
Quiet *bool `yaml:"quiet,omitempty"`
|
||||
Output *ConfigOutputType `yaml:"output,omitempty"`
|
||||
Insecure *bool `yaml:"insecure,omitempty"`
|
||||
DryRun *bool `yaml:"dryRun,omitempty"`
|
||||
Params types.Params `yaml:"params,omitempty"`
|
||||
Headers types.Headers `yaml:"headers,omitempty"`
|
||||
Cookies types.Cookies `yaml:"cookies,omitempty"`
|
||||
Bodies []string `yaml:"bodies,omitempty"`
|
||||
Proxies types.Proxies `yaml:"proxies,omitempty"`
|
||||
Values []string `yaml:"values,omitempty"`
|
||||
Lua []string `yaml:"lua,omitempty"`
|
||||
Js []string `yaml:"js,omitempty"`
|
||||
ShowConfig *bool `yaml:"showConfig,omitempty"`
|
||||
Files []types.ConfigFile `yaml:"files,omitempty"`
|
||||
Methods []string `yaml:"methods,omitempty"`
|
||||
URL *url.URL `yaml:"url,omitempty"`
|
||||
Timeout *time.Duration `yaml:"timeout,omitempty"`
|
||||
Concurrency *uint `yaml:"concurrency,omitempty"`
|
||||
Requests *uint64 `yaml:"requests,omitempty"`
|
||||
Duration *time.Duration `yaml:"duration,omitempty"`
|
||||
Progress *ConfigProgressType `yaml:"progress,omitempty"`
|
||||
Output *ConfigOutputType `yaml:"output,omitempty"`
|
||||
Insecure *bool `yaml:"insecure,omitempty"`
|
||||
DryRun *bool `yaml:"dryRun,omitempty"`
|
||||
Params types.Params `yaml:"params,omitempty"`
|
||||
Headers types.Headers `yaml:"headers,omitempty"`
|
||||
Cookies types.Cookies `yaml:"cookies,omitempty"`
|
||||
Bodies []string `yaml:"bodies,omitempty"`
|
||||
Proxies types.Proxies `yaml:"proxies,omitempty"`
|
||||
Values []string `yaml:"values,omitempty"`
|
||||
Lua []string `yaml:"lua,omitempty"`
|
||||
Js []string `yaml:"js,omitempty"`
|
||||
LogLevel *string `yaml:"logLevel,omitempty"`
|
||||
LogFile *string `yaml:"logFile,omitempty"`
|
||||
}
|
||||
|
||||
func (config Config) MarshalYAML() (any, error) {
|
||||
@@ -173,8 +187,8 @@ func (config Config) MarshalYAML() (any, error) {
|
||||
if config.Duration != nil {
|
||||
addField(content, "duration", toNode(*config.Duration), "")
|
||||
}
|
||||
if config.Quiet != nil {
|
||||
addField(content, "quiet", toNode(*config.Quiet), "")
|
||||
if config.Progress != nil {
|
||||
addField(content, "progress", toNode(string(*config.Progress)), "")
|
||||
}
|
||||
if config.Output != nil {
|
||||
addField(content, "output", toNode(string(*config.Output)), "")
|
||||
@@ -221,6 +235,13 @@ func (config Config) MarshalYAML() (any, error) {
|
||||
addStringSlice(content, "values", config.Values, false)
|
||||
addStringSlice(content, "lua", config.Lua, false)
|
||||
addStringSlice(content, "js", config.Js, false)
|
||||
if config.LogLevel != nil {
|
||||
addField(content, "logLevel", toNode(*config.LogLevel), "")
|
||||
}
|
||||
|
||||
if config.LogFile != nil {
|
||||
addField(content, "logFile", toNode(*config.LogFile), "")
|
||||
}
|
||||
|
||||
return root, nil
|
||||
}
|
||||
@@ -295,8 +316,8 @@ func (config *Config) Merge(newConfig *Config) {
|
||||
if newConfig.ShowConfig != nil {
|
||||
config.ShowConfig = newConfig.ShowConfig
|
||||
}
|
||||
if newConfig.Quiet != nil {
|
||||
config.Quiet = newConfig.Quiet
|
||||
if newConfig.Progress != nil {
|
||||
config.Progress = newConfig.Progress
|
||||
}
|
||||
if newConfig.Output != nil {
|
||||
config.Output = newConfig.Output
|
||||
@@ -331,6 +352,12 @@ func (config *Config) Merge(newConfig *Config) {
|
||||
if len(newConfig.Js) != 0 {
|
||||
config.Js = append(config.Js, newConfig.Js...)
|
||||
}
|
||||
if newConfig.LogLevel != nil {
|
||||
config.LogLevel = newConfig.LogLevel
|
||||
}
|
||||
if newConfig.LogFile != nil {
|
||||
config.LogFile = newConfig.LogFile
|
||||
}
|
||||
}
|
||||
|
||||
func (config *Config) SetDefaults() {
|
||||
@@ -361,8 +388,8 @@ func (config *Config) SetDefaults() {
|
||||
if config.ShowConfig == nil {
|
||||
config.ShowConfig = new(Defaults.ShowConfig)
|
||||
}
|
||||
if config.Quiet == nil {
|
||||
config.Quiet = new(Defaults.Quiet)
|
||||
if config.Progress == nil {
|
||||
config.Progress = new(Defaults.Progress)
|
||||
}
|
||||
if config.Insecure == nil {
|
||||
config.Insecure = new(Defaults.Insecure)
|
||||
@@ -377,6 +404,14 @@ func (config *Config) SetDefaults() {
|
||||
if config.Output == nil {
|
||||
config.Output = new(Defaults.Output)
|
||||
}
|
||||
|
||||
if config.LogLevel == nil {
|
||||
config.LogLevel = new(Defaults.LogLevel)
|
||||
}
|
||||
|
||||
if config.LogFile == nil {
|
||||
config.LogFile = new("")
|
||||
}
|
||||
}
|
||||
|
||||
// Validate validates the config fields.
|
||||
@@ -426,8 +461,21 @@ func (config Config) Validate() error {
|
||||
validationErrors = append(validationErrors, types.NewFieldValidationError("ShowConfig", "", errors.New("showConfig field is required")))
|
||||
}
|
||||
|
||||
if config.Quiet == nil {
|
||||
validationErrors = append(validationErrors, types.NewFieldValidationError("Quiet", "", errors.New("quiet field is required")))
|
||||
if config.Progress == nil {
|
||||
validationErrors = append(validationErrors, types.NewFieldValidationError("Progress", "", errors.New("progress field is required")))
|
||||
} else {
|
||||
switch *config.Progress {
|
||||
case ConfigProgressTypeBar, ConfigProgressTypeNone:
|
||||
default:
|
||||
validationErrors = append(
|
||||
validationErrors,
|
||||
types.NewFieldValidationError(
|
||||
"Progress",
|
||||
string(*config.Progress),
|
||||
fmt.Errorf("progress must be one of: %s, %s", ConfigProgressTypeBar, ConfigProgressTypeNone),
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
if config.Output == nil {
|
||||
@@ -460,6 +508,36 @@ func (config Config) Validate() error {
|
||||
validationErrors = append(validationErrors, types.NewFieldValidationError("DryRun", "", errors.New("dryRun field is required")))
|
||||
}
|
||||
|
||||
if config.LogLevel != nil {
|
||||
for i, level := range sarin.SplitLogLevels(*config.LogLevel) {
|
||||
if !slices.Contains(ValidLogLevels, level) {
|
||||
validationErrors = append(
|
||||
validationErrors,
|
||||
types.NewFieldValidationError(
|
||||
fmt.Sprintf("LogLevel[%d]", i),
|
||||
level,
|
||||
fmt.Errorf("log level must be one of: %s", strings.Join(ValidLogLevels, ", ")),
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if config.LogFile != nil && *config.LogFile != "" {
|
||||
dir := filepath.Dir(*config.LogFile)
|
||||
if info, err := os.Stat(dir); err != nil {
|
||||
validationErrors = append(
|
||||
validationErrors,
|
||||
types.NewFieldValidationError("LogFile", *config.LogFile, fmt.Errorf("parent directory %q is not accessible", dir)),
|
||||
)
|
||||
} else if !info.IsDir() {
|
||||
validationErrors = append(
|
||||
validationErrors,
|
||||
types.NewFieldValidationError("LogFile", *config.LogFile, fmt.Errorf("parent path %q is not a directory", dir)),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
for i, proxy := range config.Proxies {
|
||||
if !slices.Contains(ValidProxySchemes, proxy.Scheme) {
|
||||
validationErrors = append(
|
||||
|
||||
+74
-78
@@ -49,74 +49,6 @@ func (parser ConfigENVParser) Parse() (*Config, error) {
|
||||
config.Files = append(config.Files, *types.ParseConfigFile(configFile))
|
||||
}
|
||||
|
||||
if quiet := parser.getEnv("QUIET"); quiet != "" {
|
||||
quietParsed, err := utilsParse.ParseString[bool](quiet)
|
||||
if err != nil {
|
||||
fieldParseErrors = append(
|
||||
fieldParseErrors,
|
||||
types.NewFieldParseError(
|
||||
parser.getFullEnvName("QUIET"),
|
||||
quiet,
|
||||
errors.New("invalid value for boolean, expected 'true' or 'false'"),
|
||||
),
|
||||
)
|
||||
} else {
|
||||
config.Quiet = &quietParsed
|
||||
}
|
||||
}
|
||||
|
||||
if output := parser.getEnv("OUTPUT"); output != "" {
|
||||
config.Output = new(ConfigOutputType(output))
|
||||
}
|
||||
|
||||
if insecure := parser.getEnv("INSECURE"); insecure != "" {
|
||||
insecureParsed, err := utilsParse.ParseString[bool](insecure)
|
||||
if err != nil {
|
||||
fieldParseErrors = append(
|
||||
fieldParseErrors,
|
||||
types.NewFieldParseError(
|
||||
parser.getFullEnvName("INSECURE"),
|
||||
insecure,
|
||||
errors.New("invalid value for boolean, expected 'true' or 'false'"),
|
||||
),
|
||||
)
|
||||
} else {
|
||||
config.Insecure = &insecureParsed
|
||||
}
|
||||
}
|
||||
|
||||
if dryRun := parser.getEnv("DRY_RUN"); dryRun != "" {
|
||||
dryRunParsed, err := utilsParse.ParseString[bool](dryRun)
|
||||
if err != nil {
|
||||
fieldParseErrors = append(
|
||||
fieldParseErrors,
|
||||
types.NewFieldParseError(
|
||||
parser.getFullEnvName("DRY_RUN"),
|
||||
dryRun,
|
||||
errors.New("invalid value for boolean, expected 'true' or 'false'"),
|
||||
),
|
||||
)
|
||||
} else {
|
||||
config.DryRun = &dryRunParsed
|
||||
}
|
||||
}
|
||||
|
||||
if method := parser.getEnv("METHOD"); method != "" {
|
||||
config.Methods = []string{method}
|
||||
}
|
||||
|
||||
if urlEnv := parser.getEnv("URL"); urlEnv != "" {
|
||||
urlEnvParsed, err := url.Parse(urlEnv)
|
||||
if err != nil {
|
||||
fieldParseErrors = append(
|
||||
fieldParseErrors,
|
||||
types.NewFieldParseError(parser.getFullEnvName("URL"), urlEnv, err),
|
||||
)
|
||||
} else {
|
||||
config.URL = urlEnvParsed
|
||||
}
|
||||
}
|
||||
|
||||
if concurrency := parser.getEnv("CONCURRENCY"); concurrency != "" {
|
||||
concurrencyParsed, err := utilsParse.ParseString[uint](concurrency)
|
||||
if err != nil {
|
||||
@@ -165,22 +97,58 @@ func (parser ConfigENVParser) Parse() (*Config, error) {
|
||||
}
|
||||
}
|
||||
|
||||
if timeout := parser.getEnv("TIMEOUT"); timeout != "" {
|
||||
timeoutParsed, err := utilsParse.ParseString[time.Duration](timeout)
|
||||
if logLevel := parser.getEnv("LOG_LEVEL"); logLevel != "" {
|
||||
config.LogLevel = new(logLevel)
|
||||
}
|
||||
|
||||
if logFile := parser.getEnv("LOG_FILE"); logFile != "" {
|
||||
config.LogFile = new(logFile)
|
||||
}
|
||||
|
||||
if progress := parser.getEnv("PROGRESS"); progress != "" {
|
||||
config.Progress = new(ConfigProgressType(progress))
|
||||
}
|
||||
|
||||
if output := parser.getEnv("OUTPUT"); output != "" {
|
||||
config.Output = new(ConfigOutputType(output))
|
||||
}
|
||||
|
||||
if dryRun := parser.getEnv("DRY_RUN"); dryRun != "" {
|
||||
dryRunParsed, err := utilsParse.ParseString[bool](dryRun)
|
||||
if err != nil {
|
||||
fieldParseErrors = append(
|
||||
fieldParseErrors,
|
||||
types.NewFieldParseError(
|
||||
parser.getFullEnvName("TIMEOUT"),
|
||||
timeout,
|
||||
errors.New("invalid value for duration, expected a duration string (e.g., '10s', '1h30m')"),
|
||||
parser.getFullEnvName("DRY_RUN"),
|
||||
dryRun,
|
||||
errors.New("invalid value for boolean, expected 'true' or 'false'"),
|
||||
),
|
||||
)
|
||||
} else {
|
||||
config.Timeout = &timeoutParsed
|
||||
config.DryRun = &dryRunParsed
|
||||
}
|
||||
}
|
||||
|
||||
if urlEnv := parser.getEnv("URL"); urlEnv != "" {
|
||||
urlEnvParsed, err := url.Parse(urlEnv)
|
||||
if err != nil {
|
||||
fieldParseErrors = append(
|
||||
fieldParseErrors,
|
||||
types.NewFieldParseError(parser.getFullEnvName("URL"), urlEnv, err),
|
||||
)
|
||||
} else {
|
||||
config.URL = urlEnvParsed
|
||||
}
|
||||
}
|
||||
|
||||
if method := parser.getEnv("METHOD"); method != "" {
|
||||
config.Methods = []string{method}
|
||||
}
|
||||
|
||||
if body := parser.getEnv("BODY"); body != "" {
|
||||
config.Bodies = []string{body}
|
||||
}
|
||||
|
||||
if param := parser.getEnv("PARAM"); param != "" {
|
||||
config.Params.Parse(param)
|
||||
}
|
||||
@@ -193,10 +161,6 @@ func (parser ConfigENVParser) Parse() (*Config, error) {
|
||||
config.Cookies.Parse(cookie)
|
||||
}
|
||||
|
||||
if body := parser.getEnv("BODY"); body != "" {
|
||||
config.Bodies = []string{body}
|
||||
}
|
||||
|
||||
if proxy := parser.getEnv("PROXY"); proxy != "" {
|
||||
err := config.Proxies.Parse(proxy)
|
||||
if err != nil {
|
||||
@@ -215,6 +179,38 @@ func (parser ConfigENVParser) Parse() (*Config, error) {
|
||||
config.Values = []string{values}
|
||||
}
|
||||
|
||||
if timeout := parser.getEnv("TIMEOUT"); timeout != "" {
|
||||
timeoutParsed, err := utilsParse.ParseString[time.Duration](timeout)
|
||||
if err != nil {
|
||||
fieldParseErrors = append(
|
||||
fieldParseErrors,
|
||||
types.NewFieldParseError(
|
||||
parser.getFullEnvName("TIMEOUT"),
|
||||
timeout,
|
||||
errors.New("invalid value for duration, expected a duration string (e.g., '10s', '1h30m')"),
|
||||
),
|
||||
)
|
||||
} else {
|
||||
config.Timeout = &timeoutParsed
|
||||
}
|
||||
}
|
||||
|
||||
if insecure := parser.getEnv("INSECURE"); insecure != "" {
|
||||
insecureParsed, err := utilsParse.ParseString[bool](insecure)
|
||||
if err != nil {
|
||||
fieldParseErrors = append(
|
||||
fieldParseErrors,
|
||||
types.NewFieldParseError(
|
||||
parser.getFullEnvName("INSECURE"),
|
||||
insecure,
|
||||
errors.New("invalid value for boolean, expected 'true' or 'false'"),
|
||||
),
|
||||
)
|
||||
} else {
|
||||
config.Insecure = &insecureParsed
|
||||
}
|
||||
}
|
||||
|
||||
if lua := parser.getEnv("LUA"); lua != "" {
|
||||
config.Lua = []string{lua}
|
||||
}
|
||||
|
||||
+43
-33
@@ -192,24 +192,26 @@ func (kv *keyValuesField) unmarshalMapping(node *yaml.Node) error {
|
||||
}
|
||||
|
||||
type configYAML struct {
|
||||
ShowConfig *bool `yaml:"showConfig"`
|
||||
ConfigFiles stringOrSliceField `yaml:"configFile"`
|
||||
Method stringOrSliceField `yaml:"method"`
|
||||
URL *string `yaml:"url"`
|
||||
Timeout *time.Duration `yaml:"timeout"`
|
||||
Concurrency *uint `yaml:"concurrency"`
|
||||
RequestCount *uint64 `yaml:"requests"`
|
||||
Duration *time.Duration `yaml:"duration"`
|
||||
Quiet *bool `yaml:"quiet"`
|
||||
LogLevel *string `yaml:"logLevel"`
|
||||
LogFile *string `yaml:"logFile"`
|
||||
Progress *string `yaml:"progress"`
|
||||
Output *string `yaml:"output"`
|
||||
Insecure *bool `yaml:"insecure"`
|
||||
ShowConfig *bool `yaml:"showConfig"`
|
||||
DryRun *bool `yaml:"dryRun"`
|
||||
URL *string `yaml:"url"`
|
||||
Method stringOrSliceField `yaml:"method"`
|
||||
Bodies stringOrSliceField `yaml:"body"`
|
||||
Params keyValuesField `yaml:"params"`
|
||||
Headers keyValuesField `yaml:"headers"`
|
||||
Cookies keyValuesField `yaml:"cookies"`
|
||||
Bodies stringOrSliceField `yaml:"body"`
|
||||
Proxies stringOrSliceField `yaml:"proxy"`
|
||||
Values stringOrSliceField `yaml:"values"`
|
||||
Timeout *time.Duration `yaml:"timeout"`
|
||||
Insecure *bool `yaml:"insecure"`
|
||||
Lua stringOrSliceField `yaml:"lua"`
|
||||
Js stringOrSliceField `yaml:"js"`
|
||||
}
|
||||
@@ -231,33 +233,7 @@ func (parser ConfigFileParser) ParseYAML(data []byte) (*Config, error) {
|
||||
|
||||
var fieldParseErrors []types.FieldParseError
|
||||
|
||||
config.Methods = append(config.Methods, parsedData.Method...)
|
||||
config.Timeout = parsedData.Timeout
|
||||
config.Concurrency = parsedData.Concurrency
|
||||
config.Requests = parsedData.RequestCount
|
||||
config.Duration = parsedData.Duration
|
||||
config.ShowConfig = parsedData.ShowConfig
|
||||
config.Quiet = parsedData.Quiet
|
||||
|
||||
if parsedData.Output != nil {
|
||||
config.Output = new(ConfigOutputType(*parsedData.Output))
|
||||
}
|
||||
|
||||
config.Insecure = parsedData.Insecure
|
||||
config.DryRun = parsedData.DryRun
|
||||
for _, kv := range parsedData.Params {
|
||||
config.Params = append(config.Params, types.Param(kv))
|
||||
}
|
||||
for _, kv := range parsedData.Headers {
|
||||
config.Headers = append(config.Headers, types.Header(kv))
|
||||
}
|
||||
for _, kv := range parsedData.Cookies {
|
||||
config.Cookies = append(config.Cookies, types.Cookie(kv))
|
||||
}
|
||||
config.Bodies = append(config.Bodies, parsedData.Bodies...)
|
||||
config.Values = append(config.Values, parsedData.Values...)
|
||||
config.Lua = append(config.Lua, parsedData.Lua...)
|
||||
config.Js = append(config.Js, parsedData.Js...)
|
||||
|
||||
if len(parsedData.ConfigFiles) > 0 {
|
||||
for _, configFile := range parsedData.ConfigFiles {
|
||||
@@ -265,6 +241,22 @@ func (parser ConfigFileParser) ParseYAML(data []byte) (*Config, error) {
|
||||
}
|
||||
}
|
||||
|
||||
config.Concurrency = parsedData.Concurrency
|
||||
config.Requests = parsedData.RequestCount
|
||||
config.Duration = parsedData.Duration
|
||||
config.LogLevel = parsedData.LogLevel
|
||||
config.LogFile = parsedData.LogFile
|
||||
|
||||
if parsedData.Progress != nil {
|
||||
config.Progress = new(ConfigProgressType(*parsedData.Progress))
|
||||
}
|
||||
|
||||
if parsedData.Output != nil {
|
||||
config.Output = new(ConfigOutputType(*parsedData.Output))
|
||||
}
|
||||
|
||||
config.DryRun = parsedData.DryRun
|
||||
|
||||
if parsedData.URL != nil {
|
||||
urlParsed, err := url.Parse(*parsedData.URL)
|
||||
if err != nil {
|
||||
@@ -274,6 +266,18 @@ func (parser ConfigFileParser) ParseYAML(data []byte) (*Config, error) {
|
||||
}
|
||||
}
|
||||
|
||||
config.Methods = append(config.Methods, parsedData.Method...)
|
||||
config.Bodies = append(config.Bodies, parsedData.Bodies...)
|
||||
for _, kv := range parsedData.Params {
|
||||
config.Params = append(config.Params, types.Param(kv))
|
||||
}
|
||||
for _, kv := range parsedData.Headers {
|
||||
config.Headers = append(config.Headers, types.Header(kv))
|
||||
}
|
||||
for _, kv := range parsedData.Cookies {
|
||||
config.Cookies = append(config.Cookies, types.Cookie(kv))
|
||||
}
|
||||
|
||||
for i, proxy := range parsedData.Proxies {
|
||||
err := config.Proxies.Parse(proxy)
|
||||
if err != nil {
|
||||
@@ -284,6 +288,12 @@ func (parser ConfigFileParser) ParseYAML(data []byte) (*Config, error) {
|
||||
}
|
||||
}
|
||||
|
||||
config.Values = append(config.Values, parsedData.Values...)
|
||||
config.Timeout = parsedData.Timeout
|
||||
config.Insecure = parsedData.Insecure
|
||||
config.Lua = append(config.Lua, parsedData.Lua...)
|
||||
config.Js = append(config.Js, parsedData.Js...)
|
||||
|
||||
if len(fieldParseErrors) > 0 {
|
||||
return nil, types.NewFieldParseErrors(fieldParseErrors)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user