123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216 |
- // Package le_go provides a Golang client library for logging to
- // logentries.com over a TCP connection.
- //
- // it uses an access token for sending log events.
- package le_go
- import (
- "crypto/tls"
- "fmt"
- "net"
- "os"
- "strings"
- "sync"
- "time"
- )
- // Logger represents a Logentries logger,
- // it holds the open TCP connection, access token, prefix and flags.
- //
- // all Logger operations are thread safe and blocking,
- // log operations can be invoked in a non-blocking way by calling them from
- // a goroutine.
- type Logger struct {
- conn net.Conn
- flag int
- mu sync.Mutex
- prefix string
- token string
- buf []byte
- }
- const lineSep = "\n"
- // Connect creates a new Logger instance and opens a TCP connection to
- // logentries.com,
- // The token can be generated at logentries.com by adding a new log,
- // choosing manual configuration and token based TCP connection.
- func Connect(token string) (*Logger, error) {
- logger := Logger{
- token: token,
- }
- if err := logger.openConnection(); err != nil {
- return nil, err
- }
- return &logger, nil
- }
- // Close closes the TCP connection to logentries.com
- func (logger *Logger) Close() error {
- if logger.conn != nil {
- return logger.conn.Close()
- }
- return nil
- }
- // Opens a TCP connection to logentries.com
- func (logger *Logger) openConnection() error {
- conn, err := tls.Dial("tcp", "data.logentries.com:443", &tls.Config{})
- if err != nil {
- return err
- }
- logger.conn = conn
- return nil
- }
- // It returns if the TCP connection to logentries.com is open
- func (logger *Logger) isOpenConnection() bool {
- if logger.conn == nil {
- return false
- }
- buf := make([]byte, 1)
- logger.conn.SetReadDeadline(time.Now())
- _, err := logger.conn.Read(buf)
- switch err.(type) {
- case net.Error:
- if err.(net.Error).Timeout() == true {
- logger.conn.SetReadDeadline(time.Time{})
- return true
- }
- }
- return false
- }
- // It ensures that the TCP connection to logentries.com is open.
- // If the connection is closed, a new one is opened.
- func (logger *Logger) ensureOpenConnection() error {
- if !logger.isOpenConnection() {
- if err := logger.openConnection(); err != nil {
- return err
- }
- }
- return nil
- }
- // Fatal is same as Print() but calls to os.Exit(1)
- func (logger *Logger) Fatal(v ...interface{}) {
- logger.Output(2, fmt.Sprint(v...))
- os.Exit(1)
- }
- // Fatalf is same as Printf() but calls to os.Exit(1)
- func (logger *Logger) Fatalf(format string, v ...interface{}) {
- logger.Output(2, fmt.Sprintf(format, v...))
- os.Exit(1)
- }
- // Fatalln is same as Println() but calls to os.Exit(1)
- func (logger *Logger) Fatalln(v ...interface{}) {
- logger.Output(2, fmt.Sprintln(v...))
- os.Exit(1)
- }
- // Flags returns the logger flags
- func (logger *Logger) Flags() int {
- return logger.flag
- }
- // Output does the actual writing to the TCP connection
- func (logger *Logger) Output(calldepth int, s string) error {
- _, err := logger.Write([]byte(s))
- return err
- }
- // Panic is same as Print() but calls to panic
- func (logger *Logger) Panic(v ...interface{}) {
- s := fmt.Sprint(v...)
- logger.Output(2, s)
- panic(s)
- }
- // Panicf is same as Printf() but calls to panic
- func (logger *Logger) Panicf(format string, v ...interface{}) {
- s := fmt.Sprintf(format, v...)
- logger.Output(2, s)
- panic(s)
- }
- // Panicln is same as Println() but calls to panic
- func (logger *Logger) Panicln(v ...interface{}) {
- s := fmt.Sprintln(v...)
- logger.Output(2, s)
- panic(s)
- }
- // Prefix returns the logger prefix
- func (logger *Logger) Prefix() string {
- return logger.prefix
- }
- // Print logs a message
- func (logger *Logger) Print(v ...interface{}) {
- logger.Output(2, fmt.Sprint(v...))
- }
- // Printf logs a formatted message
- func (logger *Logger) Printf(format string, v ...interface{}) {
- logger.Output(2, fmt.Sprintf(format, v...))
- }
- // Println logs a message with a linebreak
- func (logger *Logger) Println(v ...interface{}) {
- logger.Output(2, fmt.Sprintln(v...))
- }
- // SetFlags sets the logger flags
- func (logger *Logger) SetFlags(flag int) {
- logger.flag = flag
- }
- // SetPrefix sets the logger prefix
- func (logger *Logger) SetPrefix(prefix string) {
- logger.prefix = prefix
- }
- // Write writes a bytes array to the Logentries TCP connection,
- // it adds the access token and prefix and also replaces
- // line breaks with the unicode \u2028 character
- func (logger *Logger) Write(p []byte) (n int, err error) {
- if err := logger.ensureOpenConnection(); err != nil {
- return 0, err
- }
- logger.mu.Lock()
- defer logger.mu.Unlock()
- logger.makeBuf(p)
- return logger.conn.Write(logger.buf)
- }
- // makeBuf constructs the logger buffer
- // it is not safe to be used from within multiple concurrent goroutines
- func (logger *Logger) makeBuf(p []byte) {
- count := strings.Count(string(p), lineSep)
- p = []byte(strings.Replace(string(p), lineSep, "\u2028", count-1))
- logger.buf = logger.buf[:0]
- logger.buf = append(logger.buf, (logger.token + " ")...)
- logger.buf = append(logger.buf, (logger.prefix + " ")...)
- logger.buf = append(logger.buf, p...)
- if !strings.HasSuffix(string(logger.buf), lineSep) {
- logger.buf = append(logger.buf, (lineSep)...)
- }
- }
|