github.com/sbuss/deis@v1.6.1/logger/syslogd/syslogd.go (about)

     1  package syslogd
     2  
     3  import (
     4  	"fmt"
     5  	"io"
     6  	"log"
     7  	"os"
     8  	"path"
     9  	"regexp"
    10  
    11  	"github.com/deis/deis/logger/syslog"
    12  
    13  	"github.com/deis/deis/logger/drain"
    14  )
    15  
    16  var LogRoot string
    17  
    18  type handler struct {
    19  	// To simplify implementation of our handler we embed helper
    20  	// syslog.BaseHandler struct.
    21  	*syslog.BaseHandler
    22  }
    23  
    24  // Simple fiter for named/bind messages which can be used with BaseHandler
    25  func filter(m syslog.SyslogMessage) bool {
    26  	return true
    27  }
    28  
    29  func newHandler() *handler {
    30  	h := handler{syslog.NewBaseHandler(5, filter, false)}
    31  	go h.mainLoop() // BaseHandler needs some gorutine that reads from its queue
    32  	return &h
    33  }
    34  
    35  // check if a file path exists
    36  func fileExists(path string) (bool, error) {
    37  	_, err := os.Stat(path)
    38  	if err == nil {
    39  		return true, nil
    40  	}
    41  	if os.IsNotExist(err) {
    42  		return false, nil
    43  	}
    44  	return false, err
    45  }
    46  
    47  func getLogFile(message string) (io.Writer, error) {
    48  	r := regexp.MustCompile(`^.* ([-a-z0-9]+)\[[a-z0-9-_\.]+\].*`)
    49  	match := r.FindStringSubmatch(message)
    50  	if match == nil {
    51  		return nil, fmt.Errorf("Could not find app name in message: %s", message)
    52  	}
    53  	appName := match[1]
    54  	filePath := path.Join(LogRoot, appName+".log")
    55  	// check if file exists
    56  	exists, err := fileExists(filePath)
    57  	if err != nil {
    58  		return nil, err
    59  	}
    60  	// return a new file or the existing file for appending
    61  	var file io.Writer
    62  	if exists {
    63  		file, err = os.OpenFile(filePath, os.O_RDWR|os.O_APPEND, 0644)
    64  	} else {
    65  		file, err = os.OpenFile(filePath, os.O_RDWR|os.O_CREATE, 0644)
    66  	}
    67  	return file, err
    68  }
    69  
    70  func writeToDisk(m syslog.SyslogMessage) error {
    71  	file, err := getLogFile(m.String())
    72  	if err != nil {
    73  		return err
    74  	}
    75  	bytes := []byte(m.String() + "\n")
    76  	file.Write(bytes)
    77  	return nil
    78  }
    79  
    80  // mainLoop reads from BaseHandler queue using h.Get and logs messages to stdout
    81  func (h *handler) mainLoop() {
    82  	for {
    83  		m := h.Get()
    84  		if m == nil {
    85  			break
    86  		}
    87  		d := drain.GetDrain()
    88  		if d != "" {
    89  			drain.SendToDrain(m.String(), d)
    90  		}
    91  		err := writeToDisk(m)
    92  		if err != nil {
    93  			log.Println(err)
    94  		}
    95  	}
    96  	h.End()
    97  }
    98  
    99  // Listen starts a new syslog server which runs until it receives a signal.
   100  func Listen(signalChan chan os.Signal, cleanupDone chan bool, bindAddr string) {
   101  	fmt.Println("Starting syslog...")
   102  	// If LogRoot doesn't exist, create it
   103  	// equivalent to Python's `if not os.path.exists(filename)`
   104  	if _, err := os.Stat(LogRoot); os.IsNotExist(err) {
   105  		if err = os.MkdirAll(LogRoot, 0777); err != nil {
   106  			log.Fatalf("unable to create LogRoot at %s: %v", LogRoot, err)
   107  		}
   108  	}
   109  	// Create a server with one handler and run one listen gorutine
   110  	s := syslog.NewServer()
   111  	s.AddHandler(newHandler())
   112  	s.Listen(bindAddr)
   113  	fmt.Println("Syslog server started...")
   114  	fmt.Println("deis-logger running")
   115  
   116  	// Wait for terminating signal
   117  	for _ = range signalChan {
   118  		// Shutdown the server
   119  		fmt.Println("Shutting down...")
   120  		s.Shutdown()
   121  		cleanupDone <- true
   122  	}
   123  }