Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support for custom logger in servers #371

Merged
merged 2 commits into from
Mar 28, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
63 changes: 63 additions & 0 deletions dhcpv4/server4/logger.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
package server4

import (
"github.com/insomniacslk/dhcp/dhcpv4"
)

// Logger is a handler which will be used to output logging messages
type Logger interface {
// PrintMessage print _all_ DHCP messages
PrintMessage(prefix string, message *dhcpv4.DHCPv4)

// Printf is use to print the rest debugging information
Printf(format string, v ...interface{})
}

// EmptyLogger prints nothing
type EmptyLogger struct{}

// Printf is just a dummy function that does nothing
func (e EmptyLogger) Printf(format string, v ...interface{}) {}

// PrintMessage is just a dummy function that does nothing
func (e EmptyLogger) PrintMessage(prefix string, message *dhcpv4.DHCPv4) {}

// Printfer is used for actual output of the logger. For example *log.Logger is a Printfer.
type Printfer interface {
// Printf is the function for logging output. Arguments are handled in the manner of fmt.Printf.
Printf(format string, v ...interface{})
}

// ShortSummaryLogger is a wrapper for Printfer to implement interface Logger.
// DHCP messages are printed in the short format.
type ShortSummaryLogger struct {
// Printfer is used for actual output of the logger
Printfer
}

// Printf prints a log message as-is via predefined Printfer
func (s ShortSummaryLogger) Printf(format string, v ...interface{}) {
s.Printfer.Printf(format, v...)
}

// PrintMessage prints a DHCP message in the short format via predefined Printfer
func (s ShortSummaryLogger) PrintMessage(prefix string, message *dhcpv4.DHCPv4) {
s.Printf("%s: %s", prefix, message)
}

// DebugLogger is a wrapper for Printfer to implement interface Logger.
// DHCP messages are printed in the long format.
type DebugLogger struct {
// Printfer is used for actual output of the logger
Printfer
}

// Printf prints a log message as-is via predefined Printfer
func (d DebugLogger) Printf(format string, v ...interface{}) {
d.Printfer.Printf(format, v...)
}

// PrintMessage prints a DHCP message in the long format via predefined Printfer
func (d DebugLogger) PrintMessage(prefix string, message *dhcpv4.DHCPv4) {
d.Printf("%s: %s", prefix, message.Summary())
}
40 changes: 40 additions & 0 deletions dhcpv4/server4/logger_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package server4

import(
"log"
"os"
"testing"

"github.com/insomniacslk/dhcp/dhcpv4"
"github.com/stretchr/testify/require"
)

func TestEmptyLogger(t *testing.T) {
l := EmptyLogger{}
msg, err := dhcpv4.New()
require.Nil(t, err)
l.Printf("test")
l.PrintMessage("prefix", msg)
}

func TestShortSummaryLogger(t *testing.T) {
l := ShortSummaryLogger{
Printfer: log.New(os.Stderr, "[dhcpv4] ", log.LstdFlags),
}
msg, err := dhcpv4.New()
require.Nil(t, err)
require.NotNil(t, msg)
l.Printf("test")
l.PrintMessage("prefix", msg)
}

func TestDebugLogger(t *testing.T) {
l := DebugLogger{
Printfer: log.New(os.Stderr, "[dhcpv4] ", log.LstdFlags),
}
msg, err := dhcpv4.New()
require.Nil(t, err)
require.NotNil(t, msg)
l.Printf("test")
l.PrintMessage("prefix", msg)
}
40 changes: 34 additions & 6 deletions dhcpv4/server4/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package server4
import (
"log"
"net"
"os"

"github.com/insomniacslk/dhcp/dhcpv4"
)
Expand Down Expand Up @@ -68,32 +69,33 @@ type Handler func(conn net.PacketConn, peer net.Addr, m *dhcpv4.DHCPv4)
type Server struct {
conn net.PacketConn
Handler Handler
logger Logger
}

// Serve serves requests.
func (s *Server) Serve() error {
log.Printf("Server listening on %s", s.conn.LocalAddr())
log.Print("Ready to handle requests")
s.logger.Printf("Server listening on %s", s.conn.LocalAddr())
s.logger.Printf("Ready to handle requests")

defer s.Close()
for {
rbuf := make([]byte, 4096) // FIXME this is bad
n, peer, err := s.conn.ReadFrom(rbuf)
if err != nil {
log.Printf("Error reading from packet conn: %v", err)
s.logger.Printf("Error reading from packet conn: %v", err)
return err
}
log.Printf("Handling request from %v", peer)
s.logger.Printf("Handling request from %v", peer)

m, err := dhcpv4.FromBytes(rbuf[:n])
if err != nil {
log.Printf("Error parsing DHCPv4 request: %v", err)
s.logger.Printf("Error parsing DHCPv4 request: %v", err)
continue
}

upeer, ok := peer.(*net.UDPAddr)
if !ok {
log.Printf("Not a UDP connection? Peer is %s", peer)
s.logger.Printf("Not a UDP connection? Peer is %s", peer)
continue
}
// Set peer to broadcast if the client did not have an IP.
Expand Down Expand Up @@ -126,6 +128,7 @@ func WithConn(c net.PacketConn) ServerOpt {
func NewServer(ifname string, addr *net.UDPAddr, handler Handler, opt ...ServerOpt) (*Server, error) {
s := &Server{
Handler: handler,
logger: EmptyLogger{},
}

for _, o := range opt {
Expand All @@ -141,3 +144,28 @@ func NewServer(ifname string, addr *net.UDPAddr, handler Handler, opt ...ServerO
}
return s, nil
}

// WithSummaryLogger logs one-line DHCPv4 message summaries when sent & received.
func WithSummaryLogger() ServerOpt {
return func(s *Server) {
s.logger = ShortSummaryLogger{
Printfer: log.New(os.Stderr, "[dhcpv4] ", log.LstdFlags),
}
}
}

// WithDebugLogger logs multi-line full DHCPv4 messages when sent & received.
func WithDebugLogger() ServerOpt {
return func(s *Server) {
s.logger = DebugLogger{
Printfer: log.New(os.Stderr, "[dhcpv4] ", log.LstdFlags),
}
}
}

// WithLogger set the logger (see interface Logger).
func WithLogger(newLogger Logger) ServerOpt {
return func(s *Server) {
s.logger = newLogger
}
}
63 changes: 63 additions & 0 deletions dhcpv6/server6/logger.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
package server6

import (
"github.com/insomniacslk/dhcp/dhcpv6"
)

// Logger is a handler which will be used to output logging messages
type Logger interface {
// PrintMessage print _all_ DHCP messages
PrintMessage(prefix string, message *dhcpv6.Message)

// Printf is use to print the rest debugging information
Printf(format string, v ...interface{})
}

// EmptyLogger prints nothing
type EmptyLogger struct{}

// Printf is just a dummy function that does nothing
func (e EmptyLogger) Printf(format string, v ...interface{}) {}

// PrintMessage is just a dummy function that does nothing
func (e EmptyLogger) PrintMessage(prefix string, message *dhcpv6.Message) {}

// Printfer is used for actual output of the logger. For example *log.Logger is a Printfer.
type Printfer interface {
// Printf is the function for logging output. Arguments are handled in the manner of fmt.Printf.
Printf(format string, v ...interface{})
}

// ShortSummaryLogger is a wrapper for Printfer to implement interface Logger.
// DHCP messages are printed in the short format.
type ShortSummaryLogger struct {
// Printfer is used for actual output of the logger
Printfer
}

// Printf prints a log message as-is via predefined Printfer
func (s ShortSummaryLogger) Printf(format string, v ...interface{}) {
s.Printfer.Printf(format, v...)
}

// PrintMessage prints a DHCP message in the short format via predefined Printfer
func (s ShortSummaryLogger) PrintMessage(prefix string, message *dhcpv6.Message) {
s.Printf("%s: %s", prefix, message)
}

// DebugLogger is a wrapper for Printfer to implement interface Logger.
// DHCP messages are printed in the long format.
type DebugLogger struct {
// Printfer is used for actual output of the logger
Printfer
}

// Printf prints a log message as-is via predefined Printfer
func (d DebugLogger) Printf(format string, v ...interface{}) {
d.Printfer.Printf(format, v...)
}

// PrintMessage prints a DHCP message in the long format via predefined Printfer
func (d DebugLogger) PrintMessage(prefix string, message *dhcpv6.Message) {
d.Printf("%s: %s", prefix, message.Summary())
}
40 changes: 40 additions & 0 deletions dhcpv6/server6/logger_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package server6

import(
"log"
"os"
"testing"

"github.com/insomniacslk/dhcp/dhcpv6"
"github.com/stretchr/testify/require"
)

func TestEmptyLogger(t *testing.T) {
l := EmptyLogger{}
msg, err := dhcpv6.NewMessage()
require.Nil(t, err)
l.Printf("test")
l.PrintMessage("prefix", msg)
}

func TestShortSummaryLogger(t *testing.T) {
l := ShortSummaryLogger{
Printfer: log.New(os.Stderr, "[dhcpv6] ", log.LstdFlags),
}
msg, err := dhcpv6.NewMessage()
require.Nil(t, err)
require.NotNil(t, msg)
l.Printf("test")
l.PrintMessage("prefix", msg)
}

func TestDebugLogger(t *testing.T) {
l := DebugLogger{
Printfer: log.New(os.Stderr, "[dhcpv6] ", log.LstdFlags),
}
msg, err := dhcpv6.NewMessage()
require.Nil(t, err)
require.NotNil(t, msg)
l.Printf("test")
l.PrintMessage("prefix", msg)
}
38 changes: 33 additions & 5 deletions dhcpv6/server6/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ func main() {
import (
"log"
"net"
"os"

"github.com/insomniacslk/dhcp/dhcpv6"
"golang.org/x/net/ipv6"
Expand All @@ -69,27 +70,28 @@ type Handler func(conn net.PacketConn, peer net.Addr, m dhcpv6.DHCPv6)
type Server struct {
conn net.PacketConn
handler Handler
logger Logger
}

// Serve starts the DHCPv6 server. The listener will run in background, and can
// be interrupted with `Server.Close`.
func (s *Server) Serve() error {
log.Printf("Server listening on %s", s.conn.LocalAddr())
log.Print("Ready to handle requests")
s.logger.Printf("Server listening on %s", s.conn.LocalAddr())
s.logger.Printf("Ready to handle requests")

defer s.Close()
for {
rbuf := make([]byte, 4096) // FIXME this is bad
n, peer, err := s.conn.ReadFrom(rbuf)
if err != nil {
log.Printf("Error reading from packet conn: %v", err)
s.logger.Printf("Error reading from packet conn: %v", err)
return err
}
log.Printf("Handling request from %v", peer)
s.logger.Printf("Handling request from %v", peer)

d, err := dhcpv6.FromBytes(rbuf[:n])
if err != nil {
log.Printf("Error parsing DHCPv6 request: %v", err)
s.logger.Printf("Error parsing DHCPv6 request: %v", err)
continue
}

Expand Down Expand Up @@ -125,6 +127,7 @@ func WithConn(conn net.PacketConn) ServerOpt {
func NewServer(ifname string, addr *net.UDPAddr, handler Handler, opt ...ServerOpt) (*Server, error) {
s := &Server{
handler: handler,
logger: EmptyLogger{},
}

for _, o := range opt {
Expand Down Expand Up @@ -181,3 +184,28 @@ func NewServer(ifname string, addr *net.UDPAddr, handler Handler, opt ...ServerO

return s, nil
}

// WithSummaryLogger logs one-line DHCPv6 message summaries when sent & received.
func WithSummaryLogger() ServerOpt {
return func(s *Server) {
s.logger = ShortSummaryLogger{
Printfer: log.New(os.Stderr, "[dhcpv6] ", log.LstdFlags),
}
}
}

// WithDebugLogger logs multi-line full DHCPv6 messages when sent & received.
func WithDebugLogger() ServerOpt {
return func(s *Server) {
s.logger = DebugLogger{
Printfer: log.New(os.Stderr, "[dhcpv6] ", log.LstdFlags),
}
}
}

// WithLogger set the logger (see interface Logger).
func WithLogger(newLogger Logger) ServerOpt {
return func(s *Server) {
s.logger = newLogger
}
}