{"id":13740180,"url":"https://github.com/emicklei/hazana","last_synced_at":"2025-04-14T17:06:56.157Z","repository":{"id":57492103,"uuid":"99255926","full_name":"emicklei/hazana","owner":"emicklei","description":"package to build load tests for services (http, gRPC, tcp) by implementing an Attacker","archived":false,"fork":false,"pushed_at":"2024-08-04T15:47:19.000Z","size":1451,"stargazers_count":74,"open_issues_count":0,"forks_count":10,"subscribers_count":5,"default_branch":"master","last_synced_at":"2025-04-14T17:06:50.259Z","etag":null,"topics":["golang-package","grpc","http","load-testing","performance"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/emicklei.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGES.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2017-08-03T16:57:06.000Z","updated_at":"2024-08-04T15:47:22.000Z","dependencies_parsed_at":"2024-10-22T22:28:56.800Z","dependency_job_id":null,"html_url":"https://github.com/emicklei/hazana","commit_stats":null,"previous_names":[],"tags_count":30,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/emicklei%2Fhazana","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/emicklei%2Fhazana/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/emicklei%2Fhazana/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/emicklei%2Fhazana/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/emicklei","download_url":"https://codeload.github.com/emicklei/hazana/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248923766,"owners_count":21183953,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["golang-package","grpc","http","load-testing","performance"],"created_at":"2024-08-03T04:00:43.972Z","updated_at":"2025-04-14T17:06:56.136Z","avatar_url":"https://github.com/emicklei.png","language":"Go","funding_links":[],"categories":["Tools"],"sub_categories":["Testing"],"readme":"# hazana - package for creating load tests of services\n\n[![Go](https://github.com/emicklei/hazana/actions/workflows/go.yml/badge.svg)](https://github.com/emicklei/hazana/actions/workflows/go.yml)\n[![GoDoc](https://pkg.go.dev/badge/github.com/emicklei/hazana)](https://pkg.go.dev/github.com/emicklei/hazana)\n\nHazana is created for load tests that use (generated) clients in Go to communicate to services (in any supported language).\nBy providing the Attack interface, any client and protocol could potentially be tested with this package.\nThis package was created to load test gRPC services.\n\nCompared to existing HTTP load testing tools (e.g. tsenart/vegeta) that can send raw HTTP requests, this package requires the use of client code to send the requests and receive the response.\n\n## Attack\n\n        // Attack must be implemented by a service client.\n        type Attack interface {\n                // Setup should establish the connection to the service\n                // It may want to access the config of the runner.\n                Setup(c Config) error\n\n                // Do performs one request and is executed in a separate goroutine.\n                // The context is used to cancel the request on timeout.\n                Do(ctx context.Context) DoResult\n\n                // Teardown can be used to close the connection to the service.\n                Teardown() error\n\n                // Clone should return a fresh new Attack\n                // Make sure the new Attack has values for shared struct fields initialized at Setup.\n                Clone() Attack\n        }\nThe **hazana** runner will spawn goroutines to meet this load.\nEach goroutine will use one Attack value to perform the communication ( see **Do()** ).\nTypically each Attack value uses its own connection but your implementation can use another strategy.\n\n### Rampup\n\nThe **hazana** runner will use a rampup period in which the RPS is increased (every second) during the rampup time. In this phase, new goroutines are spawned up to the given maximum. This package has two strategies for adding new attackers to meet the rps.\n\n#### linear\n\nThe **linear** rampup strategy will create exactly the maximum number of goroutines within the rampup period.\n\n#### exp2\n\nThe **exp2** strategy spawn goroutines as needed (exponential with max factor of 2) to match the current rps load during. You can change the time in seconds to measure the rate (default=1) using the `keep` parameter. The factor can be changed with the `max-factor` parameter.\nUsing the configuration:\n\n        “RampupStrategy”: “exp2 keep=5 max-factor=1.1\",\n\nAs a command line flag:\n\n        -s “exp2 keep=5 max-factor=1.1\"\n\n![profile](hazana_profile.png)\n\n### Flags\n\nPrograms that use the **hazana** package will have several flags to control the load runner.\n\n    Usage of \u003c\u003cyour load test program\u003e\u003e:\n        -attack int\n                duration of the attack in seconds (default 60)\n        -max int\n                maximum concurrent attackers (default 10)\n        -timeout int\n                timeout in seconds for an attack call (default 5)\n        -o string\n                output file to write the metrics per sample request index (use stdout if empty)\n        -csv string\n                CSV output file to write the metrics\n        -ramp int\n                ramp up time in seconds (default 10)\n        -s string\n                set the rampup strategy, possible values are {linear,exp2}\n        -rps int\n                target number of requests per second, must be greater than zero (default 1)\n        -t int\n                test your attack implementation with a number of sample calls. Your program exits after this.\n        -verbose\n                produce more verbose logging\n\n#### Example from flags\n\nAfter creating your implementation type **YourAttack** then this would be the minimal program to run a load test.\n\n        func main() {\n                r := hazana.Run(new(YourAttack), hazana.ConfigFromFlags())\n\n                // inspect the report and compute whether the test has failed\n                // e.g by looking at the success percentage and mean response time of each metric.\n                r.Failed = false\n\n                hazana.PrintReport(r)\n        }\n\n### Configuration\n\nIn addition to using flags, you can load the configuration from a JSON file. Values set with flags will override those from the configuration file.\n\n        {\n                \"RPS\": 10,\n                \"AttackTimeSec\": 20,\n                \"RampupTimeSec\": 10,                \n                \"RampupStrategy\": \"linear\",\n                \"MaxAttackers\": 10,\n                \"DoTimeoutSec\": 5,\n                \"OutputFilename\": \"myreport.json\",\n                \"Verbose\": true,\n                \"Debug\": false,\n                \"Metadata\": {\n                        \"service\" : \"happiness.services.com\",\n                        \"environment\" : \"staging\",\n                        \"version\": \"v1.42\",\n                        \"apiToken*\": \"your-secret-token\"\n                }\n        }\n\n_Note that metadata keys that end with * will be obfuscated when reporting_. \n\n#### Example from file\n\n        func main() {\n                r := hazana.Run(YourAttack{}, hazana.ConfigFromFile(\"myconfig.json\"))\n                hazana.PrintReport(r)\n                hazana.PrintSummary(r)\n        }\n\nSee **examples/zombie.go** for a complete minimal example.\n\nSee **examples/clock** for an actual gRPC service that can tell time under load.\n\n### Sample verbose output from one of our services\n\n        +1s - *** Hazana load runner ready to attack ***\n        +1s - rps [20] attack [90] rampup [30] strategy [exp2 keep=5 max-factor=1.1] max [10] timeout [60] JSON [] CSV [report.csv]\n        +1s - [8] available logical CPUs\n        +1s - ||| rampup of [30] seconds to RPS [20] within attack of [90] seconds\n        +1s - setup and spawn new attacker [1]\n        +10s - rate [0.999929 -\u003e 1], mean response [4.200527174s], requests [2], attackers [1], success [50 %]\n        +10s - setup and spawn new attacker [2]\n        +17s - rate [1.496180 -\u003e 1], mean response [2.144609037s], requests [3], attackers [2], success [66 %]\n        +22s - rate [0.624308 -\u003e 2], mean response [2.294694897s], requests [7], attackers [2], success [100 %]\n        +22s - setup and spawn new attacker [3]\n        +28s - rate [1.912042 -\u003e 2], mean response [726.317443ms], requests [10], attackers [3], success [100 %]\n        +28s - setup and spawn new attacker [4]\n        +33s - rate [0.895940 -\u003e 3], mean response [2.401489741s], requests [5], attackers [4], success [100 %]\n        +33s - setup and spawn new attacker [5]\n        +39s - rate [1.468714 -\u003e 4], mean response [2.27204947s], requests [16], attackers [5], success [93 %]\n        +39s - setup and spawn new attacker [6]\n        +44s - rate [3.861015 -\u003e 4], mean response [1.179716954s], requests [22], attackers [6], success [95 %]\n        +44s - setup and spawn new attacker [7]\n        +49s - rate [4.998839 -\u003e 5], mean response [1.186741846s], requests [25], attackers [7], success [100 %]\n        +49s - setup and spawn new attacker [8]\n        +55s - rate [3.441637 -\u003e 6], mean response [1.799351987s], requests [18], attackers [8], success [100 %]\n        +55s - setup and spawn new attacker [9]\n        +1m0s - rate [3.976226 -\u003e 6], mean response [2.055811128s], requests [25], attackers [9], success [100 %]\n        +1m0s - setup and spawn new attacker [10]\n        +1m5s - rate [3.555044 -\u003e 7], mean response [2.143760751s], requests [24], attackers [10], success [95 %]\n        +1m10s - rate [3.146333 -\u003e 8], mean response [2.618258609s], requests [15], attackers [10], success [100 %]\n        +1m15s - rate [4.270554 -\u003e 8], mean response [2.266823792s], requests [28], attackers [10], success [100 %]\n        +1m21s - rate [4.259347 -\u003e 9], mean response [2.315611968s], requests [22], attackers [10], success [100 %]\n        +1m26s - rate [5.568545 -\u003e 10], mean response [2.139091741s], requests [20], attackers [10], success [95 %]\n        +1m31s - rate [2.886864 -\u003e 10], mean response [2.436964999s], requests [25], attackers [10], success [100 %]\n        +1m36s - rate [5.345010 -\u003e 11], mean response [1.871945022s], requests [26], attackers [10], success [100 %]\n        +1m41s - rate [3.830200 -\u003e 12], mean response [1.887682054s], requests [23], attackers [10], success [100 %]\n        +1m47s - rate [3.146157 -\u003e 12], mean response [2.172577651s], requests [27], attackers [10], success [96 %]\n        +1m52s - rate [4.188442 -\u003e 13], mean response [2.130385868s], requests [25], attackers [10], success [100 %]\n        +1m57s - rate [3.782267 -\u003e 14], mean response [2.001996278s], requests [27], attackers [10], success [100 %]\n        +2m2s - rate [4.101091 -\u003e 14], mean response [1.654729749s], requests [24], attackers [10], success [95 %]\n        +2m7s - rate [3.609923 -\u003e 15], mean response [2.414714412s], requests [24], attackers [10], success [100 %]\n        +2m13s - rate [3.681610 -\u003e 16], mean response [2.316453726s], requests [23], attackers [10], success [100 %]\n        +2m18s - rate [4.531789 -\u003e 16], mean response [1.65280437s], requests [34], attackers [10], success [100 %]\n        +2m23s - rate [4.410283 -\u003e 17], mean response [2.037735812s], requests [24], attackers [10], success [95 %]\n        +2m28s - rate [3.834626 -\u003e 18], mean response [2.006833405s], requests [22], attackers [10], success [95 %]\n        +2m34s - rate [3.846774 -\u003e 18], mean response [2.391088483s], requests [26], attackers [10], success [100 %]\n        +2m40s - rate [3.027653 -\u003e 19], mean response [1.998581075s], requests [21], attackers [10], success [95 %]\n        +2m46s - rate [1.628317 -\u003e 20], mean response [3.36120323s], requests [18], attackers [10], success [94 %]\n        +2m46s - ||| rampup ending up with [10] attackers\n        +2m46s - begin full attack of [60] remaining seconds\n        +3m46s - end full attack\n        +3m46s - stopping attackers [10]\n        +3m46s - tearing down attackers [10]\n        +3m46s - CSV report written to [report.csv]\n        ---------\n        category-c\n        - - - - -\n        requests: 4\n        errors: 0\n        rps: 4.1229347790648765\n        mean: 4.571788432s\n        50th: 4.222491097s\n        95th: 4.883595542s\n        99th: 4.883595542s\n        avg kB \u003e: 0\n        avg kB \u003c: 19\n        max: 5.184646443s\n        success: 100 %\n        ---------\n        product-p\n        - - - - -\n        requests: 2\n        errors: 0\n        rps: 2.319250297795507\n        mean: 3.39725241s\n        50th: 2.817941596s\n        95th: 2.817941596s\n        99th: 2.817941596s\n        avg kB \u003e: 0\n        avg kB \u003c: 11\n        max: 3.976563224s\n        success: 100 %\n        ---------\n        search\n        - - - - -\n        requests: 4\n        errors: 0\n        rps: 0.8711446902078789\n        mean: 3.802252054s\n        50th: 4.087427907s\n        95th: 4.897371961s\n        99th: 4.897371961s\n        avg kB \u003e: 0\n        avg kB \u003c: 8\n        max: 5.792558602s\n        success: 100 %\n\n### Stackdriver integration\n\nThe [hazana-stackdriver-monitoring](https://github.com/emicklei/hazana-stackdriver-monitoring) project offers a tool to send the results of a loadtest to a Google Stackdriver account. The metrics from the load test are sent as custom metrics to Stackdriver Monitoring. The report itself is sent as a log entry to Stackdriver Logging.\n\n## Graph visualization\n\nThe [hazana-report-visualizer](https://github.com/robertalpha/hazana-report-visualizer) is a tool that produces a diagram served by a local webapp that visualizes a set of reports. It parses the JSON documents to collect the data points.\n\nThe [hazana-grafana-monitoring](https://github.com/emicklei/hazana-grafana-monitoring) package sends data to a Graphite server which data can be visualised using a Grafana dashboard. Using the \"-m\" flag you can tell your running loadtest to send this data in realtime to the dashboard (via Graphite).\n\n© 2017-2022, [ernestmicklei.com](http://ernestmicklei.com).  Apache v2 License. Contributions welcome.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Femicklei%2Fhazana","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Femicklei%2Fhazana","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Femicklei%2Fhazana/lists"}