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