mirror of
https://github.com/buger/goreplay.git
synced 2024-04-21 12:32:02 +00:00
Settings refactoring. Verbose mode. Bumb to 1.1 version
This commit is contained in:
@@ -14,7 +14,7 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
VERSION = 0.1
|
||||
VERSION = "0.1.1"
|
||||
)
|
||||
|
||||
func main() {
|
||||
|
||||
+23
-41
@@ -16,19 +16,9 @@ import (
|
||||
"os"
|
||||
"os/exec"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type ListenerSettings struct {
|
||||
networkInterface string
|
||||
port int
|
||||
|
||||
replayAddress string
|
||||
}
|
||||
|
||||
var settings ListenerSettings = ListenerSettings{}
|
||||
|
||||
type HttpRequest struct {
|
||||
Tag string // Not used yet
|
||||
Method string // Right now only 'GET'
|
||||
@@ -36,9 +26,14 @@ type HttpRequest struct {
|
||||
Headers map[string]string // Request Headers
|
||||
}
|
||||
|
||||
// Enable debug logging only if "--verbose" flag passed
|
||||
func Debug(v ...interface{}) {
|
||||
if Settings.verbose { log.Println(v...) }
|
||||
}
|
||||
|
||||
// Parse `tcpdump` output to find HTTP GET requests
|
||||
// When HttpRequest found it get send to `requests` channel
|
||||
func ParseRequest(pipe io.ReadCloser, requests chan *HttpRequest) {
|
||||
func parseRequest(pipe io.ReadCloser, requests chan *HttpRequest) {
|
||||
request_re := regexp.MustCompile("(GET) (/.*) HTTP/1.1")
|
||||
headers_re := regexp.MustCompile("([^ ]*): (.*)")
|
||||
|
||||
@@ -96,8 +91,8 @@ func ParseRequest(pipe io.ReadCloser, requests chan *HttpRequest) {
|
||||
|
||||
// Sends request to replay server via UDP
|
||||
// Before sending it encode request object using standard gob encoder
|
||||
func SendRequest(requests chan *HttpRequest) {
|
||||
serverAddr, err := net.ResolveUDPAddr("udp4", settings.replayAddress)
|
||||
func forwardRequest(requests chan *HttpRequest) {
|
||||
serverAddr, err := net.ResolveUDPAddr("udp4", Settings.ReplayServer())
|
||||
conn, err := net.DialUDP("udp", nil, serverAddr)
|
||||
|
||||
defer conn.Close()
|
||||
@@ -109,7 +104,7 @@ func SendRequest(requests chan *HttpRequest) {
|
||||
for {
|
||||
select {
|
||||
case request := <-requests:
|
||||
fmt.Println("Request:", request.Url)
|
||||
Debug("Forwarding:", request.Url, "to", Settings.ReplayServer())
|
||||
|
||||
msg := bytes.Buffer{}
|
||||
|
||||
@@ -125,6 +120,14 @@ func SendRequest(requests chan *HttpRequest) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
func greeting() {
|
||||
fmt.Println("Listening for HTTP traffic on", Settings.port, "port")
|
||||
fmt.Println("Running: tcpdump "+strings.Join(Settings.TCPDumpConfig()," "))
|
||||
fmt.Println("Forwarding requests to replay server:", Settings.ReplayServer())
|
||||
}
|
||||
|
||||
|
||||
// Because its sub-program, Run acts as `main`
|
||||
func Run() {
|
||||
if os.Getuid() != 0 {
|
||||
@@ -132,13 +135,11 @@ func Run() {
|
||||
fmt.Println("This is required since listener sniff traffic on given port.")
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
if !strings.Contains(settings.replayAddress, ":") {
|
||||
settings.replayAddress = settings.replayAddress + ":28020"
|
||||
}
|
||||
|
||||
|
||||
// TODO: use RAW_SOCKETS instead of tcpdump
|
||||
cmd := exec.Command("tcpdump", "-vv", "-A", "-i", settings.networkInterface, "port "+strconv.Itoa(settings.port))
|
||||
cmd := exec.Command("tcpdump", Settings.TCPDumpConfig()...)
|
||||
|
||||
greeting()
|
||||
|
||||
stdout, _ := cmd.StdoutPipe()
|
||||
cmd.Stderr = os.Stderr
|
||||
@@ -149,29 +150,10 @@ func Run() {
|
||||
|
||||
requests := make(chan *HttpRequest)
|
||||
|
||||
go ParseRequest(stdout, requests)
|
||||
go SendRequest(requests)
|
||||
go parseRequest(stdout, requests)
|
||||
go forwardRequest(requests)
|
||||
|
||||
if err := cmd.Wait(); err != nil {
|
||||
flag.Usage()
|
||||
}
|
||||
}
|
||||
|
||||
func init() {
|
||||
if len(os.Args) < 2 || os.Args[1] != "listen" {
|
||||
return
|
||||
}
|
||||
|
||||
const (
|
||||
defaultPort = 80
|
||||
defaultNetworkInterface = "any"
|
||||
|
||||
defaultReplayAddress = "localhost:28020"
|
||||
)
|
||||
|
||||
flag.IntVar(&settings.port, "p", defaultPort, "Specify the http server port whose traffic you want to capture")
|
||||
|
||||
flag.StringVar(&settings.networkInterface, "i", defaultNetworkInterface, "By default it try to listen on all network interfaces.To get list of interfaces run `ifconfig`")
|
||||
|
||||
flag.StringVar(&settings.replayAddress, "r", defaultReplayAddress, "Address of replay server.")
|
||||
}
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
package listener
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
"strings"
|
||||
"flag"
|
||||
"os"
|
||||
)
|
||||
|
||||
const (
|
||||
defaultPort = 80
|
||||
defaultNetworkInterface = "any"
|
||||
|
||||
defaultReplayAddress = "localhost:28020"
|
||||
)
|
||||
|
||||
type ListenerSettings struct {
|
||||
networkInterface string
|
||||
port int
|
||||
|
||||
replayAddress string
|
||||
|
||||
verbose bool
|
||||
}
|
||||
|
||||
var Settings ListenerSettings = ListenerSettings{}
|
||||
|
||||
func (s *ListenerSettings) ReplayServer() string {
|
||||
if !strings.Contains(s.replayAddress, ":") {
|
||||
return s.replayAddress + ":28020"
|
||||
}
|
||||
|
||||
return s.replayAddress
|
||||
}
|
||||
|
||||
// tcpdump -vv -A -i all port 8080
|
||||
func (s *ListenerSettings) TCPDumpConfig() []string {
|
||||
return []string{"-vv", "-A", "-i", Settings.networkInterface, "port "+strconv.Itoa(Settings.port)}
|
||||
}
|
||||
|
||||
|
||||
func init() {
|
||||
if len(os.Args) < 2 || os.Args[1] != "listen" {
|
||||
return
|
||||
}
|
||||
|
||||
flag.IntVar(&Settings.port, "p", defaultPort, "Specify the http server port whose traffic you want to capture")
|
||||
|
||||
flag.StringVar(&Settings.networkInterface, "i", defaultNetworkInterface, "By default it try to listen on all network interfaces.To get list of interfaces run `ifconfig`")
|
||||
|
||||
flag.StringVar(&Settings.replayAddress, "r", defaultReplayAddress, "Address of replay server.")
|
||||
|
||||
flag.BoolVar(&Settings.verbose, "verbose", false, "Log requests")
|
||||
}
|
||||
+9
-28
@@ -27,16 +27,16 @@ package replay
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/gob"
|
||||
"flag"
|
||||
"fmt"
|
||||
"log"
|
||||
"net"
|
||||
"os"
|
||||
)
|
||||
|
||||
const bufSize = 1024 * 10
|
||||
|
||||
var settings ReplaySettings = ReplaySettings{}
|
||||
// Enable debug logging only if "--verbose" flag passed
|
||||
func Debug(v ...interface{}) {
|
||||
if Settings.verbose { log.Println(v...) }
|
||||
}
|
||||
|
||||
// Decode HttpRequest object using standard gob decoder
|
||||
func DecodeRequest(enc []byte) (request *HttpRequest, err error) {
|
||||
@@ -57,13 +57,13 @@ func DecodeRequest(enc []byte) (request *HttpRequest, err error) {
|
||||
func Run() {
|
||||
var buf [bufSize]byte
|
||||
|
||||
addr, err := net.ResolveUDPAddr("udp", settings.Address())
|
||||
addr, err := net.ResolveUDPAddr("udp", Settings.Address())
|
||||
if err != nil {
|
||||
log.Fatal("Can't start:", err)
|
||||
}
|
||||
|
||||
conn, err := net.ListenUDP("udp", addr)
|
||||
fmt.Println("Starting replay server at:", settings.Address())
|
||||
log.Println("Starting replay server at:", Settings.Address())
|
||||
|
||||
if err != nil {
|
||||
log.Fatal("Can't start:", err)
|
||||
@@ -71,8 +71,8 @@ func Run() {
|
||||
|
||||
defer conn.Close()
|
||||
|
||||
for _, host := range settings.ForwardedHosts() {
|
||||
fmt.Println("Forwarding requests to:", host.Url, "limit:", host.Limit)
|
||||
for _, host := range Settings.ForwardedHosts() {
|
||||
log.Println("Forwarding requests to:", host.Url, "limit:", host.Limit)
|
||||
}
|
||||
|
||||
requestFactory := NewRequestFactory()
|
||||
@@ -99,23 +99,4 @@ func Run() {
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func init() {
|
||||
if len(os.Args) < 2 || os.Args[1] != "replay" {
|
||||
return
|
||||
}
|
||||
|
||||
const (
|
||||
defaultPort = 28020
|
||||
defaultHost = "0.0.0.0"
|
||||
|
||||
defaultAddress = "http://localhost:8080"
|
||||
)
|
||||
|
||||
flag.IntVar(&settings.port, "p", defaultPort, "specify port number")
|
||||
|
||||
flag.StringVar(&settings.host, "ip", defaultHost, "ip addresses to listen on")
|
||||
|
||||
flag.StringVar(&settings.forwardAddress, "f", defaultAddress, "http address to forward traffic.\n\tYou can limit requests per second by adding `|num` after address.\n\tIf you have multiple addresses with different limits. For example: http://staging.example.com|100,http://dev.example.com|10")
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,6 @@
|
||||
package replay
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
@@ -69,7 +68,7 @@ func (f *RequestFactory) sendRequest(host *ForwardHost, request *HttpRequest) {
|
||||
|
||||
// Handle incoming requests, and they responses
|
||||
func (f *RequestFactory) handleRequests() {
|
||||
hosts := settings.ForwardedHosts()
|
||||
hosts := Settings.ForwardedHosts()
|
||||
|
||||
for {
|
||||
select {
|
||||
@@ -82,10 +81,9 @@ func (f *RequestFactory) handleRequests() {
|
||||
// Increment Stat.Count
|
||||
host.Stat.IncReq()
|
||||
|
||||
fmt.Println("Sending request")
|
||||
Debug("GET ",host.Url + req.Url)
|
||||
|
||||
go f.sendRequest(host, req)
|
||||
} else {
|
||||
fmt.Println("Throttling for host:", host.Url, host.Stat.Count, host.Limit)
|
||||
}
|
||||
}
|
||||
case resp := <-f.responses:
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package replay
|
||||
|
||||
import (
|
||||
"log"
|
||||
"time"
|
||||
)
|
||||
|
||||
@@ -44,8 +43,8 @@ func (s *RequestStat) IncResp(resp *HttpResponse) {
|
||||
// Updated stats timestamp to current time and reset to zero all stats values
|
||||
// TODO: Further on reset it should write stats to file
|
||||
func (s *RequestStat) reset() {
|
||||
if s.timestamp != 0 {
|
||||
log.Println("Host:", s.host.Url, "Requests:", s.Count, "Errors:", s.Errors, "Status codes:", s.Codes)
|
||||
if s.timestamp != 0 {
|
||||
Debug("Host:", s.host.Url, "Requests:", s.Count, "Errors:", s.Errors, "Status codes:", s.Codes)
|
||||
}
|
||||
|
||||
s.timestamp = time.Now().Unix()
|
||||
|
||||
@@ -3,6 +3,8 @@ package replay
|
||||
import (
|
||||
"strconv"
|
||||
"strings"
|
||||
"os"
|
||||
"flag"
|
||||
)
|
||||
|
||||
type ForwardHost struct {
|
||||
@@ -17,6 +19,8 @@ type ReplaySettings struct {
|
||||
host string
|
||||
|
||||
forwardAddress string
|
||||
|
||||
verbose bool
|
||||
}
|
||||
|
||||
// ForwardedHosts implements forwardAddress syntax support for multiple hosts (coma separated), and rate limiting by specifing "|maxRps" after host name.
|
||||
@@ -50,3 +54,27 @@ func (r *ReplaySettings) ForwardedHosts() (hosts []*ForwardHost) {
|
||||
func (r *ReplaySettings) Address() string {
|
||||
return r.host + ":" + strconv.Itoa(r.port)
|
||||
}
|
||||
|
||||
var Settings ReplaySettings = ReplaySettings{}
|
||||
|
||||
|
||||
func init() {
|
||||
if len(os.Args) < 2 || os.Args[1] != "replay" {
|
||||
return
|
||||
}
|
||||
|
||||
const (
|
||||
defaultPort = 28020
|
||||
defaultHost = "0.0.0.0"
|
||||
|
||||
defaultAddress = "http://localhost:8080"
|
||||
)
|
||||
|
||||
flag.IntVar(&Settings.port, "p", defaultPort, "specify port number")
|
||||
|
||||
flag.StringVar(&Settings.host, "ip", defaultHost, "ip addresses to listen on")
|
||||
|
||||
flag.StringVar(&Settings.forwardAddress, "f", defaultAddress, "http address to forward traffic.\n\tYou can limit requests per second by adding `|num` after address.\n\tIf you have multiple addresses with different limits. For example: http://staging.example.com|100,http://dev.example.com|10")
|
||||
|
||||
flag.BoolVar(&Settings.verbose, "verbose", false, "Log requests")
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user