diff --git a/docs/configuration.md b/docs/configuration.md
index cb56d28..5258d0f 100644
--- a/docs/configuration.md
+++ b/docs/configuration.md
@@ -26,7 +26,9 @@ Use `-s` or `--show-config` to see the final merged configuration before sending
| [Concurrency](#concurrency) | `concurrency`
(number) | `-concurrency` / `-c`
(number) | `SARIN_CONCURRENCY`
(number) | `1` | Number of concurrent workers |
| [Requests](#requests) | `requests`
(number) | `-requests` / `-r`
(number) | `SARIN_REQUESTS`
(number) | - | Total requests to send |
| [Duration](#duration) | `duration`
(duration) | `-duration` / `-d`
(duration) | `SARIN_DURATION`
(duration) | - | Test duration |
-| [Quiet](#quiet) | `quiet`
(boolean) | `-quiet` / `-q`
(boolean) | `SARIN_QUIET`
(boolean) | `false` | Hide progress bar and logs |
+| [Log Level](#log-level) | `logLevel`
(string) | `-log-level` / `-l`
(string) | `SARIN_LOG_LEVEL`
(string) | `error` | Runtime log levels to emit |
+| [Log File](#log-file) | `logFile`
(string) | `-log-file` / `-w`
(string) | `SARIN_LOG_FILE`
(string) | - | Write runtime logs to a file |
+| [Progress](#progress) | `progress`
(string) | `-progress` / `-p`
(string) | `SARIN_PROGRESS`
(string) | `bar` | Progress display (bar/none) |
| [Output](#output) | `output`
(string) | `-output` / `-o`
(string) | `SARIN_OUTPUT`
(string) | `table` | Output format for stats |
| [Dry Run](#dry-run) | `dryRun`
(boolean) | `-dry-run` / `-z`
(boolean) | `SARIN_DRY_RUN`
(boolean) | `false` | Generate without sending |
| [Insecure](#insecure) | `insecure`
(boolean) | `-insecure` / `-I`
(boolean) | `SARIN_INSECURE`
(boolean) | `false` | Skip TLS verification |
@@ -131,7 +133,7 @@ sarin -U "http://example.com/users/{{ fakeit_UUID }}" -r 1000 -c 10
## Method
-HTTP method(s). If multiple values are provided, Sarin starts at a random index and cycles through them in order. Once the cycle completes, it picks a new random starting point. Supports [templating](templating.md).
+HTTP method(s). Defaults to `GET`. If multiple values are provided, Sarin starts at a random index and cycles through them in order. Once the cycle completes, it picks a new random starting point. Supports [templating](templating.md).
**YAML example:**
@@ -141,9 +143,9 @@ method: GET
# OR
method:
- - GET
- - POST
- - PUT
+ - GET
+ - POST
+ - PUT
```
**CLI example:**
@@ -160,7 +162,7 @@ SARIN_METHOD=GET
## Timeout
-Request timeout. Must be greater than 0.
+Request timeout. Must be greater than 0. Defaults to `10s`.
Valid time units: `ns`, `us` (or `µs`), `ms`, `s`, `m`, `h`
@@ -168,7 +170,7 @@ Valid time units: `ns`, `us` (or `µs`), `ms`, `s`, `m`, `h`
## Concurrency
-Number of concurrent workers. Must be between 1 and 100,000,000.
+Number of concurrent workers. Must be between 1 and 100,000,000. Defaults to `1`.
## Requests
@@ -182,15 +184,34 @@ Valid time units: `ns`, `us` (or `µs`), `ms`, `s`, `m`, `h`
**Examples:** `1m30s`, `25s`, `1h`
-## Quiet
+## Log Level
-Hide the progress bar and runtime logs.
+Runtime log levels to emit, comma-separated. Valid levels: `info`, `error`. Defaults to `error`.
+
+- `error`: errors that occur while generating or sending a request
+- `info`: every completed response
+
+Leave empty to disable logging entirely.
+
+**Examples:** `error` (only errors), `info` (only responses), `info,error` (both)
+
+## Log File
+
+Write runtime logs to this file instead of the terminal or stderr. The parent directory must exist.
+
+```sh
+sarin -U http://example.com -r 1000 --log-file ./run.log
+```
+
+## Progress
+
+Progress display. Valid values: `bar` (default), `none`. Use `none` to hide the progress bar.
## Output
Output format for response statistics.
-Valid formats: `table`, `json`, `yaml`, `none`
+Valid formats: `table` (default), `json`, `yaml`, `none`
Using `none` disables output and reduces memory usage since response statistics are not stored.
@@ -214,9 +235,9 @@ body: '{"product": "car"}'
# OR
body:
- - '{"product": "car"}'
- - '{"product": "phone"}'
- - '{"product": "watch"}'
+ - '{"product": "car"}'
+ - '{"product": "phone"}'
+ - '{"product": "watch"}'
```
**CLI example:**
@@ -241,19 +262,19 @@ When the same key appears as **separate entries** (in CLI or config file), all v
```yaml
params:
- key1: value1
- key2: [value2, value3] # cycles between value2 and value3
+ key1: value1
+ key2: [value2, value3] # cycles between value2 and value3
# OR
params:
- - key1: value1
- - key2: [value2, value3] # cycles between value2 and value3
+ - key1: value1
+ - key2: [value2, value3] # cycles between value2 and value3
# To send both values in every request, use separate entries:
params:
- - key2: value2
- - key2: value3 # both sent in every request
+ - key2: value2
+ - key2: value3 # both sent in every request
```
**CLI example:**
@@ -278,19 +299,19 @@ When the same key appears as **separate entries** (in CLI or config file), all v
```yaml
headers:
- key1: value1
- key2: [value2, value3] # cycles between value2 and value3
+ key1: value1
+ key2: [value2, value3] # cycles between value2 and value3
# OR
headers:
- - key1: value1
- - key2: [value2, value3] # cycles between value2 and value3
+ - key1: value1
+ - key2: [value2, value3] # cycles between value2 and value3
# To send both values in every request, use separate entries:
headers:
- - key2: value2
- - key2: value3 # both sent in every request
+ - key2: value2
+ - key2: value3 # both sent in every request
```
**CLI example:**
@@ -315,19 +336,19 @@ When the same key appears as **separate entries** (in CLI or config file), all v
```yaml
cookies:
- key1: value1
- key2: [value2, value3] # cycles between value2 and value3
+ key1: value1
+ key2: [value2, value3] # cycles between value2 and value3
# OR
cookies:
- - key1: value1
- - key2: [value2, value3] # cycles between value2 and value3
+ - key1: value1
+ - key2: [value2, value3] # cycles between value2 and value3
# To send both values in every request, use separate entries:
cookies:
- - key2: value2
- - key2: value3 # both sent in every request
+ - key2: value2
+ - key2: value3 # both sent in every request
```
**CLI example:**
@@ -356,9 +377,9 @@ proxy: http://proxy1.com
# OR
proxy:
- - http://proxy1.com
- - socks5://proxy2.com
- - socks5h://proxy3.com
+ - http://proxy1.com
+ - socks5://proxy2.com
+ - socks5h://proxy3.com
```
**CLI example:**
@@ -387,9 +408,9 @@ values: "key=value"
# OR
values: |
- key1=value1
- key2=value2
- key3=value3
+ key1=value1
+ key2=value2
+ key3=value3
```
**CLI example:**
diff --git a/docs/examples.md b/docs/examples.md
index 1095594..b30f139 100644
--- a/docs/examples.md
+++ b/docs/examples.md
@@ -13,6 +13,7 @@ This guide provides practical examples for common Sarin use cases.
- [File Uploads](#file-uploads)
- [Using Proxies](#using-proxies)
- [Output Formats](#output-formats)
+- [Runtime Logging](#runtime-logging)
- [Docker Usage](#docker-usage)
- [Dry Run Mode](#dry-run-mode)
- [Show Configuration](#show-configuration)
@@ -836,10 +837,10 @@ output: none
-**Quiet mode (hide progress bar):**
+**Hide the progress bar:**
```sh
-sarin -U http://example.com -r 1000 -c 10 -q
+sarin -U http://example.com -r 1000 -c 10 -p none
```
@@ -849,7 +850,42 @@ sarin -U http://example.com -r 1000 -c 10 -q
url: http://example.com
requests: 1000
concurrency: 10
-quiet: true
+progress: none
+```
+
+
+
+## Runtime Logging
+
+`--log-level` selects which runtime logs Sarin emits (comma-separated `info` and `error`, default `error`). `error` covers request and generation errors, `info` covers every completed response (status, duration, headers, body). Logs appear in the progress log box on an interactive terminal, go to stderr when piped, or go to a file with `--log-file`.
+
+**Log responses and errors:**
+
+```sh
+sarin -U http://example.com -r 1000 -c 10 -l info,error
+```
+
+**Write logs to a file (the progress bar stays on screen):**
+
+```sh
+sarin -U http://example.com -r 1000 -c 10 -l info --log-file ./run.log
+```
+
+**Capture logs while keeping results on stdout:**
+
+```sh
+sarin -U http://example.com -r 1000 -l info -o json > stats.json 2> run.log
+```
+
+
+YAML equivalent
+
+```yaml
+url: http://example.com
+requests: 1000
+concurrency: 10
+logLevel: info,error
+logFile: ./run.log
```
diff --git a/docs/templating.md b/docs/templating.md
index 336627b..1d2873e 100644
--- a/docs/templating.md
+++ b/docs/templating.md
@@ -183,19 +183,19 @@ body: '{{ body_FormData "image" "@https://example.com/photo.jpg" }}'
# Mixed text fields and files
body: |
- {{ body_FormData
- "title" "My Report"
- "author" "John Doe"
- "cover" "@/path/to/cover.jpg"
- "document" "@/path/to/report.pdf"
- }}
+ {{ body_FormData
+ "title" "My Report"
+ "author" "John Doe"
+ "cover" "@/path/to/cover.jpg"
+ "document" "@/path/to/report.pdf"
+ }}
# Multiple files with same field name
body: |
- {{ body_FormData
- "files" "@/path/to/file1.pdf"
- "files" "@/path/to/file2.pdf"
- }}
+ {{ body_FormData
+ "files" "@/path/to/file1.pdf"
+ "files" "@/path/to/file2.pdf"
+ }}
# Escape @ for literal value (sends "@username")
body: '{{ body_FormData "twitter" "@@username" }}'
@@ -226,7 +226,7 @@ body: '{"file": "{{ file_Base64 "/path/to/document.pdf" }}", "filename": "docume
body: '{"image": "{{ file_Base64 "https://example.com/photo.jpg" }}"}'
# Combined with values for reuse
-values: "FILE_DATA={{ file_Base64 \"/path/to/file.bin\" }}"
+values: 'FILE_DATA={{ file_Base64 "/path/to/file.bin" }}'
body: '{"data": "{{ .Values.FILE_DATA }}"}'
```
@@ -234,7 +234,7 @@ body: '{"data": "{{ .Values.FILE_DATA }}"}'
Captcha functions solve a captcha challenge through a third-party solving service and return the resulting token, which can then be embedded directly into a request. They are intended for load testing endpoints protected by reCAPTCHA, hCaptcha, or Cloudflare Turnstile.
-The functions are organized by service: `twocaptcha_*`, `anticaptcha_*`, and `capsolver_*`. Each accepts the API key as the first argument so no global configuration is required — bring your own key and use any of the supported services per template.
+The functions are organized by service: `twocaptcha_*`, `anticaptcha_*`, and `capsolver_*`. Each accepts the API key as the first argument so no global configuration is required. Bring your own key and use any of the supported services per template.
> **Important: performance and cost:**
>