add logging

This commit is contained in:
decauwsemaecker.glen@gmail.com 2017-04-06 19:32:59 -05:00
parent 689360936b
commit f028e6bbc8
6 changed files with 47 additions and 17 deletions

View File

@ -2,6 +2,5 @@
TODO:
+ Decent Logging;
+ README Documentation;
+ Unit-Tests;

View File

@ -3,6 +3,7 @@ package main
import (
"flag"
"fmt"
"log"
"os"
"time"
@ -11,8 +12,8 @@ import (
// CLI Flags
var (
timeout = flag.Duration("t", time.Second*2, "consensus's voting timeout")
verbose = flag.Bool("v", false, "verbose logging")
timeout = flag.Duration("t", time.Second*5, "consensus's voting timeout")
verbose = flag.Bool("v", false, "log errors to STDERR, when defined")
)
func main() {
@ -22,11 +23,15 @@ func main() {
cfg.WithTimeout(*timeout)
}
// TODO: Add Logging (and use the verbose flag)
// optionally create the logger,
// if no logger is defined, all logs will be discarded.
var logger *log.Logger
if verbose != nil && *verbose {
logger = externalip.NewLogger(os.Stderr)
}
// create the consensus
consensus := externalip.DefaultConsensus(
externalip.DefaultConsensusConfig().WithTimeout(*timeout))
consensus := externalip.DefaultConsensus(cfg, logger)
// retrieve the external ip
ip, err := consensus.ExternalIP()

View File

@ -1,7 +1,7 @@
package externalip
import (
"fmt"
"log"
"net"
"sync"
"time"
@ -20,8 +20,8 @@ func DefaultConsensusConfig() *ConsensusConfig {
// with default and recommended HTTPSources.
// TLS-Protected providers get more power,
// compared to plain-text providers.
func DefaultConsensus(cfg *ConsensusConfig) *Consensus {
consensus := NewConsensus(cfg)
func DefaultConsensus(cfg *ConsensusConfig, logger *log.Logger) *Consensus {
consensus := NewConsensus(cfg, logger)
// TLS-protected providers
consensus.AddVoter(NewHTTPSource("https://icanhazip.com/"), 3)
@ -34,7 +34,6 @@ func DefaultConsensus(cfg *ConsensusConfig) *Consensus {
consensus.AddVoter(NewHTTPSource("http://whatismyip.akamai.com/"), 1)
consensus.AddVoter(NewHTTPSource("http://tnx.nl/ip"), 1)
consensus.AddVoter(NewHTTPSource("http://myip.dnsomatic.com/"), 1)
consensus.AddVoter(NewHTTPSource("http://ipecho.net/plain"), 1)
consensus.AddVoter(NewHTTPSource("http://diagnostic.opendns.com/myip"), 1)
return consensus
@ -42,12 +41,16 @@ func DefaultConsensus(cfg *ConsensusConfig) *Consensus {
// NewConsensus creates a new Consensus, with no sources.
// When the given cfg is <nil>, the `DefaultConsensusConfig` will be used.
func NewConsensus(cfg *ConsensusConfig) *Consensus {
func NewConsensus(cfg *ConsensusConfig, logger *log.Logger) *Consensus {
if cfg == nil {
cfg = DefaultConsensusConfig()
}
if logger == nil {
logger = NewLogger(nil)
}
return &Consensus{
timeout: cfg.Timeout,
logger: logger,
}
}
@ -70,6 +73,7 @@ func (cfg *ConsensusConfig) WithTimeout(timeout time.Duration) *ConsensusConfig
type Consensus struct {
voters []voter
timeout time.Duration
logger *log.Logger
}
// AddVoter adds a voter to this consensus.
@ -103,7 +107,7 @@ func (c *Consensus) ExternalIP() (net.IP, error) {
wg.Add(1)
go func(v voter) {
defer wg.Done()
ip, err := v.source.IP(c.timeout)
ip, err := v.source.IP(c.timeout, c.logger)
if err == nil && ip != nil {
vlock.Lock()
defer vlock.Unlock()
@ -116,9 +120,6 @@ func (c *Consensus) ExternalIP() (net.IP, error) {
// or until the voting process times out
select {
case <-waitWG(&wg):
fmt.Println("done!") // TODO: Log instead
case <-time.After(c.timeout):
fmt.Println("timeout!") // TODO: Log instead
}
// if no votes were casted succesfully,

18
log.go Normal file
View File

@ -0,0 +1,18 @@
package externalip
import (
"io"
"io/ioutil"
"log"
)
// NewLogger returns a new standard logger, with a given writer.
// if w is <nil>, all logs will be discarded.
func NewLogger(w io.Writer) *log.Logger {
if w == nil {
w = ioutil.Discard
}
return log.New(w, "",
log.Ldate|log.Ltime|log.Lmicroseconds|log.Llongfile|log.Lshortfile)
}

View File

@ -2,6 +2,7 @@ package externalip
import (
"io/ioutil"
"log"
"net"
"net/http"
"strings"
@ -37,11 +38,12 @@ func (s *HTTPSource) WithParser(parser ContentParser) *HTTPSource {
}
// IP implements Source.IP
func (s *HTTPSource) IP(timeout time.Duration) (net.IP, error) {
func (s *HTTPSource) IP(timeout time.Duration, logger *log.Logger) (net.IP, error) {
// Define the GET method with the correct url,
// setting the User-Agent to our library
req, err := http.NewRequest("GET", s.url, nil)
if err != nil {
logger.Printf("[ERROR] could not create a GET Request for %q: %v\n", s.url, err)
return nil, err
}
req.Header.Set("User-Agent", "go-external-ip (github.com/glendc/go-external-ip)")
@ -50,12 +52,14 @@ func (s *HTTPSource) IP(timeout time.Duration) (net.IP, error) {
// Do the request and read the body for non-error results.
resp, err := client.Do(req)
if err != nil {
logger.Printf("[ERROR] could not GET %q: %v\n", s.url, err)
return nil, err
}
defer resp.Body.Close()
bytes, err := ioutil.ReadAll(resp.Body)
if err != nil {
logger.Printf("[ERROR] could not read response from %q: %v\n", s.url, err)
return nil, err
}
@ -64,6 +68,7 @@ func (s *HTTPSource) IP(timeout time.Duration) (net.IP, error) {
if s.parser != nil {
raw, err = s.parser(raw)
if err != nil {
logger.Printf("[ERROR] could not parse response from %q: %v\n", s.url, err)
return nil, err
}
}
@ -71,6 +76,7 @@ func (s *HTTPSource) IP(timeout time.Duration) (net.IP, error) {
// validate the IP
externalIP := net.ParseIP(strings.TrimSpace(raw))
if externalIP == nil {
logger.Printf("[ERROR] %q returned an invalid IP: %v\n", s.url, err)
return nil, InvalidIPError(raw)
}

View File

@ -1,6 +1,7 @@
package externalip
import (
"log"
"net"
"time"
)
@ -11,7 +12,7 @@ type Source interface {
// net.IP should never be <nil> when error is <nil>
// It is recommended that the IP function times out,
// if no result could be found, after the given timeout duration.
IP(timeout time.Duration) (net.IP, error)
IP(timeout time.Duration, logger *log.Logger) (net.IP, error)
}
// voter adds weight to the IP given by a source.