Settings refactoring. Verbose mode. Bumb to 1.1 version

This commit is contained in:
Leonid Bugaev
2013-06-03 17:53:40 +06:00
parent 51ed4e12ca
commit 236ef48e13
7 changed files with 120 additions and 78 deletions
+1 -1
View File
@@ -14,7 +14,7 @@ import (
)
const (
VERSION = 0.1
VERSION = "0.1.1"
)
func main() {
+23 -41
View File
@@ -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.")
}
+54
View File
@@ -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
View File
@@ -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")
}
}
+3 -5
View File
@@ -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:
+2 -3
View File
@@ -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()
+28
View File
@@ -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")
}