<commit_before>// +build !windows

package template

import (
	"path/filepath"
	"strings"
	"testing"
	"time"

	"github.com/google/go-cmp/cmp"
)

func TestParse(t *testing.T) {
	cases := []struct {
		File   string
		Result *Template
		Err    bool
	}{
		/*
		 * Builders
		 */
		{
			"parse-basic.json",
			&Template{
				Builders: map[string]*Builder{
					"something": {
						Name: "something",
						Type: "something",
					},
				},
			},
			false,
		},
		{
			"parse-builder-no-type.json",
			nil,
			true,
		},
		{
			"parse-builder-repeat.json",
			nil,
			true,
		},

		/*
		 * Provisioners
		 */
		{
			"parse-provisioner-basic.json",
			&Template{
				Provisioners: []*Provisioner{
					{
						Type: "something",
					},
				},
			},
			false,
		},

		{
			"parse-provisioner-pause-before.json",
			&Template{
				Provisioners: []*Provisioner{
					{
						Type:        "something",
						PauseBefore: 1 * time.Second,
					},
				},
			},
			false,
		},

		{
			"parse-provisioner-only.json",
			&Template{
				Provisioners: []*Provisioner{
					{
						Type: "something",
						OnlyExcept: OnlyExcept{
							Only: []string{"foo"},
						},
					},
				},
			},
			false,
		},

		{
			"parse-provisioner-except.json",
			&Template{
				Provisioners: []*Provisioner{
					{
						Type: "something",
						OnlyExcept: OnlyExcept{
							Except: []string{"foo"},
						},
					},
				},
			},
			false,
		},

		{
			"parse-provisioner-override.json",
			&Template{
				Provisioners: []*Provisioner{
					{
						Type: "something",
						Override: map[string]interface{}{
							"foo": map[string]interface{}{},
						},
					},
				},
			},
			false,
		},

		{
			"parse-provisioner-no-type.json",
			nil,
			true,
		},

		{
			"parse-variable-default.json",
			&Template{
				Variables: map[string]*Variable{
					"foo": {
						Default: "foo",
					},
				},
			},
			false,
		},

		{
			"parse-variable-required.json",
			&Template{
				Variables: map[string]*Variable{
					"foo": {
						Required: true,
					},
				},
			},
			false,
		},

		{
			"parse-pp-basic.json",
			&Template{
				PostProcessors: [][]*PostProcessor{
					{
						{
							Type: "foo",
							Config: map[string]interface{}{
								"foo": "bar",
							},
						},
					},
				},
			},
			false,
		},

		{
			"parse-pp-keep.json",
			&Template{
				PostProcessors: [][]*PostProcessor{
					{
						{
							Type:              "foo",
							KeepInputArtifact: true,
						},
					},
				},
			},
			false,
		},

		{
			"parse-pp-only.json",
			&Template{
				PostProcessors: [][]*PostProcessor{
					{
						{
							Type: "foo",
							OnlyExcept: OnlyExcept{
								Only: []string{"bar"},
							},
						},
					},
				},
			},
			false,
		},

		{
			"parse-pp-except.json",
			&Template{
				PostProcessors: [][]*PostProcessor{
					{
						{
							Type: "foo",
							OnlyExcept: OnlyExcept{
								Except: []string{"bar"},
							},
						},
					},
				},
			},
			false,
		},

		{
			"parse-pp-string.json",
			&Template{
				PostProcessors: [][]*PostProcessor{
					{
						{
							Type: "foo",
						},
					},
				},
			},
			false,
		},

		{
			"parse-pp-map.json",
			&Template{
				PostProcessors: [][]*PostProcessor{
					{
						{
							Type: "foo",
						},
					},
				},
			},
			false,
		},

		{
			"parse-pp-slice.json",
			&Template{
				PostProcessors: [][]*PostProcessor{
					{
						{
							Type: "foo",
						},
					},
					{
						{
							Type: "bar",
						},
					},
				},
			},
			false,
		},

		{
			"parse-pp-multi.json",
			&Template{
				PostProcessors: [][]*PostProcessor{
					{
						{
							Type: "foo",
						},
						{
							Type: "bar",
						},
					},
				},
			},
			false,
		},

		{
			"parse-pp-no-type.json",
			nil,
			true,
		},

		{
			"parse-description.json",
			&Template{
				Description: "foo",
			},
			false,
		},

		{
			"parse-min-version.json",
			&Template{
				MinVersion: "1.2",
			},
			false,
		},

		{
			"parse-push.json",
			&Template{
				Push: Push{
					Name: "foo",
				},
			},
			false,
		},

		{
			"parse-comment.json",
			&Template{
				Builders: map[string]*Builder{
					"something": {
						Name: "something",
						Type: "something",
					},
				},
			},
			false,
		},
	}

	for i, tc := range cases {
		path, _ := filepath.Abs(fixtureDir(tc.File))
		tpl, err := ParseFile(fixtureDir(tc.File))
		if (err != nil) != tc.Err {
			t.Fatalf("err: %s", err)
		}

		if tc.Result != nil {
			tc.Result.Path = path
		}
		if tpl != nil {
			tpl.RawContents = nil
		}
		if diff := cmp.Diff(tpl, tc.Result); diff != "" {
			t.Fatalf("[%d]bad: %v", i, diff)
		}
	}
}

func TestParse_contents(t *testing.T) {
	tpl, err := ParseFile(fixtureDir("parse-contents.json"))
	if err != nil {
		t.Fatalf("err: %s", err)
	}

	actual := strings.TrimSpace(string(tpl.RawContents))
	expected := `{"builders":[{"type":"test"}]}`
	if actual != expected {
		t.Fatalf("bad: %s\n\n%s", actual, expected)
	}
}

func TestParse_bad(t *testing.T) {
	cases := []struct {
		File     string
		Expected string
	}{
		{"error-beginning.json", "line 1, column 1 (offset 1)"},
		{"error-middle.json", "line 5, column 6 (offset 50)"},
		{"error-end.json", "line 1, column 30 (offset 30)"},
		{"malformed.json", "line 16, column 3 (offset 433)"},
	}
	for _, tc := range cases {
		_, err := ParseFile(fixtureDir(tc.File))
		if err == nil {
			t.Fatalf("expected error")
		}
		if !strings.Contains(err.Error(), tc.Expected) {
			t.Fatalf("file: %s\nExpected: %s\n%s\n", tc.File, tc.Expected, err.Error())
		}
	}
}
<commit_msg>template/parse_test.go: name the post-processors to their type as it's now the default<commit_after>// +build !windows

package template

import (
	"path/filepath"
	"strings"
	"testing"
	"time"

	"github.com/google/go-cmp/cmp"
)

func TestParse(t *testing.T) {
	cases := []struct {
		File   string
		Result *Template
		Err    bool
	}{
		/*
		 * Builders
		 */
		{
			"parse-basic.json",
			&Template{
				Builders: map[string]*Builder{
					"something": {
						Name: "something",
						Type: "something",
					},
				},
			},
			false,
		},
		{
			"parse-builder-no-type.json",
			nil,
			true,
		},
		{
			"parse-builder-repeat.json",
			nil,
			true,
		},

		/*
		 * Provisioners
		 */
		{
			"parse-provisioner-basic.json",
			&Template{
				Provisioners: []*Provisioner{
					{
						Type: "something",
					},
				},
			},
			false,
		},

		{
			"parse-provisioner-pause-before.json",
			&Template{
				Provisioners: []*Provisioner{
					{
						Type:        "something",
						PauseBefore: 1 * time.Second,
					},
				},
			},
			false,
		},

		{
			"parse-provisioner-only.json",
			&Template{
				Provisioners: []*Provisioner{
					{
						Type: "something",
						OnlyExcept: OnlyExcept{
							Only: []string{"foo"},
						},
					},
				},
			},
			false,
		},

		{
			"parse-provisioner-except.json",
			&Template{
				Provisioners: []*Provisioner{
					{
						Type: "something",
						OnlyExcept: OnlyExcept{
							Except: []string{"foo"},
						},
					},
				},
			},
			false,
		},

		{
			"parse-provisioner-override.json",
			&Template{
				Provisioners: []*Provisioner{
					{
						Type: "something",
						Override: map[string]interface{}{
							"foo": map[string]interface{}{},
						},
					},
				},
			},
			false,
		},

		{
			"parse-provisioner-no-type.json",
			nil,
			true,
		},

		{
			"parse-variable-default.json",
			&Template{
				Variables: map[string]*Variable{
					"foo": {
						Default: "foo",
					},
				},
			},
			false,
		},

		{
			"parse-variable-required.json",
			&Template{
				Variables: map[string]*Variable{
					"foo": {
						Required: true,
					},
				},
			},
			false,
		},

		{
			"parse-pp-basic.json",
			&Template{
				PostProcessors: [][]*PostProcessor{
					{
						{
							Name: "foo",
							Type: "foo",
							Config: map[string]interface{}{
								"foo": "bar",
							},
						},
					},
				},
			},
			false,
		},

		{
			"parse-pp-keep.json",
			&Template{
				PostProcessors: [][]*PostProcessor{
					{
						{
							Name:              "foo",
							Type:              "foo",
							KeepInputArtifact: true,
						},
					},
				},
			},
			false,
		},

		{
			"parse-pp-only.json",
			&Template{
				PostProcessors: [][]*PostProcessor{
					{
						{
							Name: "foo",
							Type: "foo",
							OnlyExcept: OnlyExcept{
								Only: []string{"bar"},
							},
						},
					},
				},
			},
			false,
		},

		{
			"parse-pp-except.json",
			&Template{
				PostProcessors: [][]*PostProcessor{
					{
						{
							Name: "foo",
							Type: "foo",
							OnlyExcept: OnlyExcept{
								Except: []string{"bar"},
							},
						},
					},
				},
			},
			false,
		},

		{
			"parse-pp-string.json",
			&Template{
				PostProcessors: [][]*PostProcessor{
					{
						{
							Name: "foo",
							Type: "foo",
						},
					},
				},
			},
			false,
		},

		{
			"parse-pp-map.json",
			&Template{
				PostProcessors: [][]*PostProcessor{
					{
						{
							Name: "foo",
							Type: "foo",
						},
					},
				},
			},
			false,
		},

		{
			"parse-pp-slice.json",
			&Template{
				PostProcessors: [][]*PostProcessor{
					{
						{
							Name: "foo",
							Type: "foo",
						},
					},
					{
						{
							Name: "bar",
							Type: "bar",
						},
					},
				},
			},
			false,
		},

		{
			"parse-pp-multi.json",
			&Template{
				PostProcessors: [][]*PostProcessor{
					{
						{
							Name: "foo",
							Type: "foo",
						},
						{
							Name: "bar",
							Type: "bar",
						},
					},
				},
			},
			false,
		},

		{
			"parse-pp-no-type.json",
			nil,
			true,
		},

		{
			"parse-description.json",
			&Template{
				Description: "foo",
			},
			false,
		},

		{
			"parse-min-version.json",
			&Template{
				MinVersion: "1.2",
			},
			false,
		},

		{
			"parse-push.json",
			&Template{
				Push: Push{
					Name: "foo",
				},
			},
			false,
		},

		{
			"parse-comment.json",
			&Template{
				Builders: map[string]*Builder{
					"something": {
						Name: "something",
						Type: "something",
					},
				},
			},
			false,
		},
	}

	for i, tc := range cases {
		path, _ := filepath.Abs(fixtureDir(tc.File))
		tpl, err := ParseFile(fixtureDir(tc.File))
		if (err != nil) != tc.Err {
			t.Fatalf("err: %s", err)
		}

		if tc.Result != nil {
			tc.Result.Path = path
		}
		if tpl != nil {
			tpl.RawContents = nil
		}
		if diff := cmp.Diff(tpl, tc.Result); diff != "" {
			t.Fatalf("[%d]bad: %v", i, diff)
		}
	}
}

func TestParse_contents(t *testing.T) {
	tpl, err := ParseFile(fixtureDir("parse-contents.json"))
	if err != nil {
		t.Fatalf("err: %s", err)
	}

	actual := strings.TrimSpace(string(tpl.RawContents))
	expected := `{"builders":[{"type":"test"}]}`
	if actual != expected {
		t.Fatalf("bad: %s\n\n%s", actual, expected)
	}
}

func TestParse_bad(t *testing.T) {
	cases := []struct {
		File     string
		Expected string
	}{
		{"error-beginning.json", "line 1, column 1 (offset 1)"},
		{"error-middle.json", "line 5, column 6 (offset 50)"},
		{"error-end.json", "line 1, column 30 (offset 30)"},
		{"malformed.json", "line 16, column 3 (offset 433)"},
	}
	for _, tc := range cases {
		_, err := ParseFile(fixtureDir(tc.File))
		if err == nil {
			t.Fatalf("expected error")
		}
		if !strings.Contains(err.Error(), tc.Expected) {
			t.Fatalf("file: %s\nExpected: %s\n%s\n", tc.File, tc.Expected, err.Error())
		}
	}
}
<|endoftext|>


<commit_before>package immortal

import (
	"bufio"
	"io"
	"log"
	"os"
	"os/exec"
	"os/signal"
	"strings"
	"syscall"
	"time"

	"github.com/immortal/logrotate"
	"github.com/immortal/multiwriter"
)

// Logger interface
type Logger interface {
	Log(input io.ReadCloser)
	IsLogging() bool
}

// LogWriter implements Logger
type LogWriter struct {
	logger *log.Logger
}

// NewLogger return a Logger instance
func NewLogger(cfg *Config, quit chan struct{}) *log.Logger {
	var (
		err     error
		file, w io.WriteCloser
	)

	// create a multiwriter
	multi := multiwriter.New()
	var m *multiwriter.MultiWriter = multi.(*multiwriter.MultiWriter)

	if cfg.Log.File != "" {
		lr, err := logrotate.New(cfg.Log.File, cfg.Log.Age, cfg.Log.Num, cfg.Log.Size)
		if err != nil {
			log.Printf("Failed to open log file %q: %s\n", cfg.Log.File, err)
		} else {
			// rotate logs when receiving an USR1
			c := make(chan os.Signal, 1)
			signal.Notify(c, syscall.SIGUSR1)
			go func() {
				for {
					<-c
					lr.Rotate()
				}
			}()
			file = lr
			m.Append(file)
		}
	}

	if cfg.Logger != "" {

		ch := make(chan error)

		runLogger := func() error {
			command := strings.Fields(cfg.Logger)
			cmd := exec.Command(command[0], command[1:]...)
			w, err = cmd.StdinPipe()
			if err != nil {
				return err
			}
			if err := cmd.Start(); err != nil {
				return err
			}
			go func() {
				ch <- cmd.Wait()
			}()
			return nil
		}

		if err := runLogger(); err != nil {
			log.Printf("logger error: %s", err)
		} else {

			// keep logger up
			go func() {
				for {
					select {
					case <-quit:
						w.Close()
						return
					case err := <-ch:
						log.Printf("logger %s", err)
						m.Remove(w)
						time.Sleep(time.Second)
						if err := runLogger(); err == nil {
							m.Append(w)
						}
					}
				}
			}()

			m.Append(w)
		}
	}

	// create the logger
	if m.Len() > 0 {
		return log.New(multi, "", 0)
	}
	return nil
}

// Log write to the logger
func (l *LogWriter) Log(input io.ReadCloser) {
	in := bufio.NewScanner(input)
	for in.Scan() {
		l.logger.Print(in.Text())
	}
	input.Close()
}

// IsLogging return true if an availale logger exists
func (l *LogWriter) IsLogging() bool {
	return l.logger != nil
}
<commit_msg>rotate only at start<commit_after>package immortal

import (
	"bufio"
	"io"
	"log"
	"os/exec"
	"strings"
	"time"

	"github.com/immortal/logrotate"
	"github.com/immortal/multiwriter"
)

// Logger interface
type Logger interface {
	Log(input io.ReadCloser)
	IsLogging() bool
}

// LogWriter implements Logger
type LogWriter struct {
	logger *log.Logger
}

// NewLogger return a Logger instance
func NewLogger(cfg *Config, quit chan struct{}) *log.Logger {
	var (
		err     error
		file, w io.WriteCloser
	)

	// create a multiwriter
	multi := multiwriter.New()
	var m *multiwriter.MultiWriter = multi.(*multiwriter.MultiWriter)

	if cfg.Log.File != "" {
		if file, err = logrotate.New(cfg.Log.File, cfg.Log.Age, cfg.Log.Num, cfg.Log.Size); err != nil {
			log.Printf("Failed to open log file %q: %s\n", cfg.Log.File, err)
		} else {
			m.Append(file)
		}
	}

	if cfg.Logger != "" {

		ch := make(chan error)

		runLogger := func() error {
			command := strings.Fields(cfg.Logger)
			cmd := exec.Command(command[0], command[1:]...)
			w, err = cmd.StdinPipe()
			if err != nil {
				return err
			}
			if err := cmd.Start(); err != nil {
				return err
			}
			go func() {
				ch <- cmd.Wait()
			}()
			return nil
		}

		if err := runLogger(); err != nil {
			log.Printf("logger error: %s", err)
		} else {

			// keep logger up
			go func() {
				for {
					select {
					case <-quit:
						w.Close()
						return
					case err := <-ch:
						log.Printf("logger %s", err)
						m.Remove(w)
						time.Sleep(time.Second)
						if err := runLogger(); err == nil {
							m.Append(w)
						}
					}
				}
			}()

			m.Append(w)
		}
	}

	// create the logger
	if m.Len() > 0 {
		return log.New(multi, "", 0)
	}
	return nil
}

// Log write to the logger
func (l *LogWriter) Log(input io.ReadCloser) {
	in := bufio.NewScanner(input)
	for in.Scan() {
		l.logger.Print(in.Text())
	}
	input.Close()
}

// IsLogging return true if an availale logger exists
func (l *LogWriter) IsLogging() bool {
	return l.logger != nil
}
<|endoftext|>


<commit_before>// Copyright © 2009--2013 The Web.go Authors
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.

package web

import (
	"log"
	"net/http"
)

// Log one request by calling every method in the order defined below. Logging
// may be done in a separate goroutine from handling. Arguments are passed by
// reference for efficiency but MUST NOT be changed!
type OneAccessLogger interface {
	// Called with the raw incoming request
	LogRequest(*http.Request)
	// Parameters as parsed by web.go
	LogParams(Params)
	// Called when headers are set by handler and will be written to client
	LogHeader(status int, header http.Header)
	// Called when response has been written to client. If an error occurred at
	// any point during handling it is passed as an argument. Otherwise err is
	// nil.
	LogDone(err error)
}

type plainOneAccessLogger struct{ *log.Logger }

func (l plainOneAccessLogger) LogRequest(req *http.Request) {
	l.Printf("%s %s", req.Method, req.URL.Path)
}

func (l plainOneAccessLogger) LogParams(p Params) {
	l.Printf("Params: %v\n", p)
}

func (l plainOneAccessLogger) LogHeader(status int, h http.Header) {
}

func (l plainOneAccessLogger) LogDone(err error) {
}

type coloredOneAccessLogger struct{ *log.Logger }

func (l coloredOneAccessLogger) LogRequest(req *http.Request) {
	l.Printf("\033[32;1m%s %s\033[0m", req.Method, req.URL.Path)
}

func (l coloredOneAccessLogger) LogParams(p Params) {
	l.Printf("\033[37;1mParams: %v\033[0m\n", p)
}

func (l coloredOneAccessLogger) LogHeader(status int, h http.Header) {
}

func (l coloredOneAccessLogger) LogDone(err error) {
}

// Factory function that generates new one-shot access loggers
type AccessLogger func(*Server) OneAccessLogger

// Simple stateless access logger that prints all requests to server.Logger
func DefaultAccessLogger(s *Server) OneAccessLogger {
	if s.Config.ColorOutput {
		return coloredOneAccessLogger{s.Logger}
	} else {
		return plainOneAccessLogger{s.Logger}
	}
}
<commit_msg>Go 1.0 compatible if { return } else { return }<commit_after>// Copyright © 2009--2013 The Web.go Authors
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.

package web

import (
	"log"
	"net/http"
)

// Log one request by calling every method in the order defined below. Logging
// may be done in a separate goroutine from handling. Arguments are passed by
// reference for efficiency but MUST NOT be changed!
type OneAccessLogger interface {
	// Called with the raw incoming request
	LogRequest(*http.Request)
	// Parameters as parsed by web.go
	LogParams(Params)
	// Called when headers are set by handler and will be written to client
	LogHeader(status int, header http.Header)
	// Called when response has been written to client. If an error occurred at
	// any point during handling it is passed as an argument. Otherwise err is
	// nil.
	LogDone(err error)
}

type plainOneAccessLogger struct{ *log.Logger }

func (l plainOneAccessLogger) LogRequest(req *http.Request) {
	l.Printf("%s %s", req.Method, req.URL.Path)
}

func (l plainOneAccessLogger) LogParams(p Params) {
	l.Printf("Params: %v\n", p)
}

func (l plainOneAccessLogger) LogHeader(status int, h http.Header) {
}

func (l plainOneAccessLogger) LogDone(err error) {
}

type coloredOneAccessLogger struct{ *log.Logger }

func (l coloredOneAccessLogger) LogRequest(req *http.Request) {
	l.Printf("\033[32;1m%s %s\033[0m", req.Method, req.URL.Path)
}

func (l coloredOneAccessLogger) LogParams(p Params) {
	l.Printf("\033[37;1mParams: %v\033[0m\n", p)
}

func (l coloredOneAccessLogger) LogHeader(status int, h http.Header) {
}

func (l coloredOneAccessLogger) LogDone(err error) {
}

// Factory function that generates new one-shot access loggers
type AccessLogger func(*Server) OneAccessLogger

// Simple stateless access logger that prints all requests to server.Logger
func DefaultAccessLogger(s *Server) OneAccessLogger {
	if s.Config.ColorOutput {
		return coloredOneAccessLogger{s.Logger}
	}
	return plainOneAccessLogger{s.Logger}
}
<|endoftext|>


<commit_before>// Package logger provides a logging framework similar to those of python
// and haskell.
package logger

import (
	"errors"
	"fmt"
	"io"
	"os"
	"strings"
	"text/template"
	"time"
)

// Format represents the format which will be used to print the message
// for an logger.
type Format string

// Logger represent different lognames and priorities. They can have
// parents and child loggers which will inherit the priority of the
// parent if it has none. The hirachy of loggers is represented through
// sepperation with dots ('.'). The root logger has the name '.'.
type Logger string

type message struct {
	Time string
	Logger
	Priority string
	Message  string
}

type logger struct {
	Logger
	Priority
	Format
	TimeFormat string
}

// Priority defines how important a log message is. Loggers will output
// messages which are above their priority level.
type Priority int

// Different priority levels ordered by their severity.
const (
	Debug Priority = iota
	Info
	Notice
	Warning
	Error
	Critical
	Alert
	Emergency
)

// DefaultPriority of the root logger.
const (
	DefaultPriority Priority = Notice
)

const (
	defroot      = Logger(".")
	defseperator = "."
)

var (
	format     = "[{{.Time}} {{.Logger}} {{.Priority}}] - {{.Message}}.\n"
	timeformat = time.RFC3339

	priorities     map[Priority]string
	loggers        map[Logger]logger
	formattemplate template.Template
)

func init() {
	loggers = make(map[Logger]logger)
	l := logger{Logger: defroot,
		Priority:   DefaultPriority,
		Format:     Format(format),
		TimeFormat: timeformat,
	}

	loggers[defroot] = l

	priorities = make(map[Priority]string)
	priorities[Debug] = "Debug"
	priorities[Info] = "Info"
	priorities[Notice] = "Notice"
	priorities[Warning] = "Warning"
	priorities[Error] = "Error"
	priorities[Critical] = "Critical"
	priorities[Alert] = "Alert"
	priorities[Emergency] = "Emergency"
}

// SetLevel sets the priority level for the logger which should be
// logged.
func SetLevel(lo Logger, pr Priority) (err error) {
	err = errors.New("this priority does not exist")

	for k := range priorities {
		if k == pr {
			err = nil
			break
		}
	}

	if err != nil {
		return
	}

	l := logger{Logger: lo,
		Priority:   pr,
		Format:     Format(format),
		TimeFormat: timeformat,
	}

	loggers[lo] = l
	return
}

// GetLevel returns the priority level of the given logger.
func GetLevel(lo Logger) (pri Priority) {
	l, e := loggers[lo]
	if e {
		pri = l.Priority
	} else {
		pri = getParentLevel(lo)
	}

	return
}

func getParentLevel(lo Logger) (pri Priority) {
	p := getParent(lo)
	pri = GetLevel(p)

	return
}

func getParent(lo Logger) (log Logger) {
	// Return root if root
	if lo == defroot {
		log = defroot
		return
	}

	s := strings.Split(string(lo), defseperator)

	// Return root if first level logger
	if len(s) == 1 {
		log = defroot
		return
	}

	// Return root if parent is empty
	if s[0] == "" {
		log = defroot
		return
	}

	l := len(s) - 1
	z := s[0:l]

	log = Logger(strings.Join(z, defseperator))

	return
}

func getLogger(lo Logger) (log logger) {
	l, e := loggers[lo]
	if e {
		log = l
	} else {
		log = getParentLogger(lo)
	}

	return
}

func getParentLogger(lo Logger) (log logger) {
	l := getParent(lo)
	log = getLogger(l)
	log.Logger = lo

	return
}

// ParsePriority tries to parse the priority by the given string.
func ParsePriority(pr string) Priority {
	for k, v := range priorities {
		if v == pr {
			return k
		}
	}

	e := errors.New("Can not parse " + pr + ". Using DefaultPriority")
	ErrorM("logger.ParsePriority", e)
	return DefaultPriority
}

// NamePriority returns the string value of the given priority.
func NamePriority(pr Priority) string {
	return priorities[pr]
}

// SetFormat changes the message format for the given logger. Avaivable
// fields are:
//
// Time: The time when the message is printed.
//
// Logger: The name of the logger.
//
// Priority: The priority of the logger.
//
// Message: The output message.
//
// The default Format is:
//
// "[{{.Time}} {{.Logger}} {{.Priority}}] - {{.Message}}.\n"
func SetFormat(lo Logger, fo Format) (err error) {
	l := getLogger(lo)
	l.Format = fo
	loggers[lo] = l

	return
}

// SetTimeFormat sets the TimeFormat which will be used in the message
// format for the specified logger
//
// The default format is: RFC3339
func SetTimeFormat(lo Logger, fo string) (err error) {
	l := getLogger(lo)
	l.TimeFormat = fo
	loggers[lo] = l

	return
}

// LogM logs a message using the given logger at a given priority.
func LogM(lo Logger, pr Priority, me ...interface{}) {
	l := getLogger(lo)

	if l.Priority > pr {
		return
	}

	printMessage(l, pr, os.Stderr, me...)
}

func printMessage(lo logger, pr Priority, wr io.Writer, me ...interface{}) {
	m := new(message)
	m.Time = time.Now().Format(string(lo.TimeFormat))
	m.Logger = lo.Logger
	m.Priority = priorities[pr]
	m.Message = fmt.Sprint(me...)

	s := formatMessage(m, lo.Format)

	fmt.Fprint(wr, s)
}

func formatMessage(me *message, fo Format) (so string) {
	so = strings.Replace(string(fo), "{{.Time}}", me.Time, -1)
	so = strings.Replace(so, "{{.Logger}}", string(me.Logger), -1)
	so = strings.Replace(so, "{{.Priority}}", me.Priority, -1)
	so = strings.Replace(so, "{{.Message}}", me.Message, -1)

	return
}

// DebugM logs a message with the Debug priority.
func DebugM(lo Logger, me ...interface{}) {
	LogM(lo, Debug, me...)
}

// InfoM logs a message with the Debug priority.
func InfoM(lo Logger, me ...interface{}) {
	LogM(lo, Info, me...)
}

// NoticeM logs a message with the Debug priority.
func NoticeM(lo Logger, me ...interface{}) {
	LogM(lo, Notice, me...)
}

// WarningM logs a message with the Debug priority.
func WarningM(lo Logger, me ...interface{}) {
	LogM(lo, Warning, me...)
}

// ErrorM logs a message with the Debug priority.
func ErrorM(lo Logger, me ...interface{}) {
	LogM(lo, Error, me...)
}

// CriticalM logs a message with the Debug priority.
func CriticalM(lo Logger, me ...interface{}) {
	LogM(lo, Critical, me...)
}

// AlertM logs a message with the Debug priority.
func AlertM(lo Logger, me ...interface{}) {
	LogM(lo, Alert, me...)
}

// EmergencyM logs a message with the Debug priority.
func EmergencyM(lo Logger, me ...interface{}) {
	LogM(lo, Emergency, me...)
}
<commit_msg>Added NewLogger function which will create a new logger with the given name<commit_after>// Package logger provides a logging framework similar to those of python
// and haskell.
package logger

import (
	"errors"
	"fmt"
	"io"
	"os"
	"strings"
	"text/template"
	"time"
)

// Format represents the format which will be used to print the message
// for an logger.
type Format string

// Logger represent different lognames and priorities. They can have
// parents and child loggers which will inherit the priority of the
// parent if it has none. The hirachy of loggers is represented through
// sepperation with dots ('.'). The root logger has the name '.'.
type Logger string

type message struct {
	Time string
	Logger
	Priority string
	Message  string
}

type logger struct {
	Logger
	Priority
	Format
	TimeFormat string
}

// Priority defines how important a log message is. Loggers will output
// messages which are above their priority level.
type Priority int

// Different priority levels ordered by their severity.
const (
	Debug Priority = iota
	Info
	Notice
	Warning
	Error
	Critical
	Alert
	Emergency
)

// DefaultPriority of the root logger.
const (
	DefaultPriority Priority = Notice
)

const (
	defroot      = Logger(".")
	defseperator = "."
)

var (
	format     = "[{{.Time}} {{.Logger}} {{.Priority}}] - {{.Message}}.\n"
	timeformat = time.RFC3339

	priorities     map[Priority]string
	loggers        map[Logger]logger
	formattemplate template.Template
)

func init() {
	loggers = make(map[Logger]logger)
	l := logger{Logger: defroot,
		Priority:   DefaultPriority,
		Format:     Format(format),
		TimeFormat: timeformat,
	}

	loggers[defroot] = l

	priorities = make(map[Priority]string)
	priorities[Debug] = "Debug"
	priorities[Info] = "Info"
	priorities[Notice] = "Notice"
	priorities[Warning] = "Warning"
	priorities[Error] = "Error"
	priorities[Critical] = "Critical"
	priorities[Alert] = "Alert"
	priorities[Emergency] = "Emergency"
}

// NewLogger will return a logger with the given name.
func NewLogger(na string) (log Logger) {
	return Logger(na)
}

// SetLevel sets the priority level for the logger which should be
// logged.
func SetLevel(lo Logger, pr Priority) (err error) {
	err = errors.New("this priority does not exist")

	for k := range priorities {
		if k == pr {
			err = nil
			break
		}
	}

	if err != nil {
		return
	}

	l := logger{Logger: lo,
		Priority:   pr,
		Format:     Format(format),
		TimeFormat: timeformat,
	}

	loggers[lo] = l
	return
}

// GetLevel returns the priority level of the given logger.
func GetLevel(lo Logger) (pri Priority) {
	l, e := loggers[lo]
	if e {
		pri = l.Priority
	} else {
		pri = getParentLevel(lo)
	}

	return
}

func getParentLevel(lo Logger) (pri Priority) {
	p := getParent(lo)
	pri = GetLevel(p)

	return
}

func getParent(lo Logger) (log Logger) {
	// Return root if root
	if lo == defroot {
		log = defroot
		return
	}

	s := strings.Split(string(lo), defseperator)

	// Return root if first level logger
	if len(s) == 1 {
		log = defroot
		return
	}

	// Return root if parent is empty
	if s[0] == "" {
		log = defroot
		return
	}

	l := len(s) - 1
	z := s[0:l]

	log = Logger(strings.Join(z, defseperator))

	return
}

func getLogger(lo Logger) (log logger) {
	l, e := loggers[lo]
	if e {
		log = l
	} else {
		log = getParentLogger(lo)
	}

	return
}

func getParentLogger(lo Logger) (log logger) {
	l := getParent(lo)
	log = getLogger(l)
	log.Logger = lo

	return
}

// ParsePriority tries to parse the priority by the given string.
func ParsePriority(pr string) Priority {
	for k, v := range priorities {
		if v == pr {
			return k
		}
	}

	e := errors.New("Can not parse " + pr + ". Using DefaultPriority")
	ErrorM("logger.ParsePriority", e)
	return DefaultPriority
}

// NamePriority returns the string value of the given priority.
func NamePriority(pr Priority) string {
	return priorities[pr]
}

// SetFormat changes the message format for the given logger. Avaivable
// fields are:
//
// Time: The time when the message is printed.
//
// Logger: The name of the logger.
//
// Priority: The priority of the logger.
//
// Message: The output message.
//
// The default Format is:
//
// "[{{.Time}} {{.Logger}} {{.Priority}}] - {{.Message}}.\n"
func SetFormat(lo Logger, fo Format) (err error) {
	l := getLogger(lo)
	l.Format = fo
	loggers[lo] = l

	return
}

// SetTimeFormat sets the TimeFormat which will be used in the message
// format for the specified logger
//
// The default format is: RFC3339
func SetTimeFormat(lo Logger, fo string) (err error) {
	l := getLogger(lo)
	l.TimeFormat = fo
	loggers[lo] = l

	return
}

// LogM logs a message using the given logger at a given priority.
func LogM(lo Logger, pr Priority, me ...interface{}) {
	l := getLogger(lo)

	if l.Priority > pr {
		return
	}

	printMessage(l, pr, os.Stderr, me...)
}

func printMessage(lo logger, pr Priority, wr io.Writer, me ...interface{}) {
	m := new(message)
	m.Time = time.Now().Format(string(lo.TimeFormat))
	m.Logger = lo.Logger
	m.Priority = priorities[pr]
	m.Message = fmt.Sprint(me...)

	s := formatMessage(m, lo.Format)

	fmt.Fprint(wr, s)
}

func formatMessage(me *message, fo Format) (so string) {
	so = strings.Replace(string(fo), "{{.Time}}", me.Time, -1)
	so = strings.Replace(so, "{{.Logger}}", string(me.Logger), -1)
	so = strings.Replace(so, "{{.Priority}}", me.Priority, -1)
	so = strings.Replace(so, "{{.Message}}", me.Message, -1)

	return
}

// DebugM logs a message with the Debug priority.
func DebugM(lo Logger, me ...interface{}) {
	LogM(lo, Debug, me...)
}

// InfoM logs a message with the Debug priority.
func InfoM(lo Logger, me ...interface{}) {
	LogM(lo, Info, me...)
}

// NoticeM logs a message with the Debug priority.
func NoticeM(lo Logger, me ...interface{}) {
	LogM(lo, Notice, me...)
}

// WarningM logs a message with the Debug priority.
func WarningM(lo Logger, me ...interface{}) {
	LogM(lo, Warning, me...)
}

// ErrorM logs a message with the Debug priority.
func ErrorM(lo Logger, me ...interface{}) {
	LogM(lo, Error, me...)
}

// CriticalM logs a message with the Debug priority.
func CriticalM(lo Logger, me ...interface{}) {
	LogM(lo, Critical, me...)
}

// AlertM logs a message with the Debug priority.
func AlertM(lo Logger, me ...interface{}) {
	LogM(lo, Alert, me...)
}

// EmergencyM logs a message with the Debug priority.
func EmergencyM(lo Logger, me ...interface{}) {
	LogM(lo, Emergency, me...)
}
<|endoftext|>


<commit_before>package negroni

import (
	"bytes"

	"log"
	"net/http"
	"os"
	"sync"
	"text/template"
	"time"
)

// Log is the structure
// passed to the template.
type Log struct {
	StartTime string
	Status    int
	Duration  time.Duration
	Hostname  string
	Method    string
	Path      string
}

// DefaultFormat is the format
// logged used by the default Logger instance.
var DefaultFormat = "{{.StartTime}} | {{.Status}} | \t {{.Duration}} | {{.Hostname}} | {{.Method}} {{.Path}} \n"

// DefaultDateFormat is the
// format used for date by the
// default Logger instance.
var DefaultDateFormat = time.RFC3339

// ALogger interface
type ALogger interface {
	Println(v ...interface{})
	Printf(format string, v ...interface{})
}

// Logger is a middleware handler that logs the request as it goes in and the response as it goes out.
type Logger struct {
	// ALogger implements just enough log.Logger interface to be compatible with other implementations
	ALogger
	dateFormat string
	template   *template.Template
	buffer     *bytes.Buffer
	mu         sync.Mutex
}

// NewLogger returns a new Logger instance
func NewLogger() *Logger {
	logger := &Logger{ALogger: log.New(os.Stdout, "[negroni] ", 0), dateFormat: DefaultDateFormat, buffer: bytes.NewBufferString("")}
	logger.SetFormat(DefaultFormat)
	return logger
}

func (l *Logger) SetFormat(format string) {
	l.template = template.Must(template.New("negroni_parser").Parse(format))
}

func (l *Logger) SetDateFormat(format string) {
	l.dateFormat = format
}

func (l *Logger) ServeHTTP(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc) {
	start := time.Now()

	next(rw, r)

	res := rw.(ResponseWriter)
	log := Log{start.Format(l.dateFormat), res.Status(), time.Since(start), r.Host, r.Method, r.URL.Path}

	l.mu.Lock()
	defer l.mu.Unlock()
	l.template.Execute(l.buffer, log)
	l.Printf(l.buffer.String())
	l.buffer.Reset()
}
<commit_msg>Rename variables and allocate a buffer each time.<commit_after>package negroni

import (
	"bytes"

	"log"
	"net/http"
	"os"
	"sync"
	"text/template"
	"time"
)

// LoggerEntry is the structure
// passed to the template.
type LoggerEntry struct {
	StartTime string
	Status    int
	Duration  time.Duration
	Hostname  string
	Method    string
	Path      string
}

// LoggerDefaultFormat is the format
// logged used by the default Logger instance.
var LoggerDefaultFormat = "{{.StartTime}} | {{.Status}} | \t {{.Duration}} | {{.Hostname}} | {{.Method}} {{.Path}} \n"

// LoggerDefaultDateFormat is the
// format used for date by the
// default Logger instance.
var LoggerDefaultDateFormat = time.RFC3339

// ALogger interface
type ALogger interface {
	Println(v ...interface{})
	Printf(format string, v ...interface{})
}

// Logger is a middleware handler that logs the request as it goes in and the response as it goes out.
type Logger struct {
	// ALogger implements just enough log.Logger interface to be compatible with other implementations
	ALogger
	dateFormat string
	template   *template.Template
}

// NewLogger returns a new Logger instance
func NewLogger() *Logger {
	logger := &Logger{ALogger: log.New(os.Stdout, "[negroni] ", 0), dateFormat: LoggerDefaultDateFormat}
	logger.SetFormat(LoggerDefaultDateFormat)
	return logger
}

func (l *Logger) SetFormat(format string) {
	l.template = template.Must(template.New("negroni_parser").Parse(format))
}

func (l *Logger) SetDateFormat(format string) {
	l.dateFormat = format
}

func (l *Logger) ServeHTTP(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc) {
	start := time.Now()

	next(rw, r)

	res := rw.(ResponseWriter)
	log := LoggerEntry{
		StartTime: start.Format(l.dateFormat),
		Status:    res.Status(),
		Duration:  time.Since(start),
		Hostname:  r.Host,
		Method:    r.Method,
		Path:      r.URL.Path,
	}

	buff := &bytes.Buffer{}
	l.template.Execute(buff, log)
	l.Printf(buff.String())
}
<|endoftext|>


<commit_before>package osdn

import (
	"fmt"
	"net"
	"strings"
	"time"

	log "github.com/golang/glog"

	"github.com/openshift/openshift-sdn/pkg/netutils"
	"github.com/openshift/openshift-sdn/plugins/osdn/api"

	kubetypes "k8s.io/kubernetes/pkg/kubelet/types"
	utildbus "k8s.io/kubernetes/pkg/util/dbus"
	kerrors "k8s.io/kubernetes/pkg/util/errors"
	kexec "k8s.io/kubernetes/pkg/util/exec"
	"k8s.io/kubernetes/pkg/util/iptables"
)

type PluginHooks interface {
	PluginStartMaster(clusterNetworkCIDR string, clusterBitsPerSubnet uint, serviceNetworkCIDR string) error
	PluginStartNode(mtu uint) error
	UpdatePod(namespace string, name string, id kubetypes.DockerID) error
}

type OvsController struct {
	pluginHooks     PluginHooks
	Registry        *Registry
	localIP         string
	localSubnet     *api.Subnet
	hostName        string
	subnetAllocator *netutils.SubnetAllocator
	sig             chan struct{}
	podNetworkReady chan struct{}
	flowController  FlowController
	VNIDMap         map[string]uint
	netIDManager    *netutils.NetIDAllocator
	adminNamespaces []string
	services        map[string]api.Service
}

type FlowController interface {
	Setup(localSubnetCIDR, clusterNetworkCIDR, serviceNetworkCIDR string, mtu uint) error

	AddOFRules(nodeIP, nodeSubnetCIDR, localIP string) error
	DelOFRules(nodeIP, localIP string) error

	AddServiceOFRules(netID uint, IP string, protocol api.ServiceProtocol, port uint) error
	DelServiceOFRules(netID uint, IP string, protocol api.ServiceProtocol, port uint) error
}

// Called by plug factory functions to initialize the generic plugin instance
func (oc *OvsController) BaseInit(registry *Registry, flowController FlowController, pluginHooks PluginHooks, hostname string, selfIP string) error {
	if hostname == "" {
		output, err := kexec.New().Command("uname", "-n").CombinedOutput()
		if err != nil {
			return err
		}
		hostname = strings.TrimSpace(string(output))
	}

	if selfIP == "" {
		var err error
		selfIP, err = netutils.GetNodeIP(hostname)
		if err != nil {
			return err
		}
	}
	log.Infof("Self IP: %s.", selfIP)

	oc.pluginHooks = pluginHooks
	oc.Registry = registry
	oc.flowController = flowController
	oc.localIP = selfIP
	oc.hostName = hostname
	oc.VNIDMap = make(map[string]uint)
	oc.sig = make(chan struct{})
	oc.podNetworkReady = make(chan struct{})
	oc.adminNamespaces = make([]string, 0)
	oc.services = make(map[string]api.Service)

	return nil
}

func (oc *OvsController) validateClusterNetwork(networkCIDR string, subnetsInUse []string, hostIPNets []*net.IPNet) error {
	clusterIP, clusterIPNet, err := net.ParseCIDR(networkCIDR)
	if err != nil {
		return fmt.Errorf("Failed to parse network address: %s", networkCIDR)
	}

	errList := []error{}
	for _, ipNet := range hostIPNets {
		if ipNet.Contains(clusterIP) {
			errList = append(errList, fmt.Errorf("Error: Cluster IP: %s conflicts with host network: %s", clusterIP.String(), ipNet.String()))
		}
		if clusterIPNet.Contains(ipNet.IP) {
			errList = append(errList, fmt.Errorf("Error: Host network with IP: %s conflicts with cluster network: %s", ipNet.IP.String(), networkCIDR))
		}
	}

	for _, netStr := range subnetsInUse {
		subnetIP, _, err := net.ParseCIDR(netStr)
		if err != nil {
			errList = append(errList, fmt.Errorf("Failed to parse network address: %s", netStr))
			continue
		}
		if !clusterIPNet.Contains(subnetIP) {
			errList = append(errList, fmt.Errorf("Error: Existing node subnet: %s is not part of cluster network: %s", netStr, networkCIDR))
		}
	}
	return kerrors.NewAggregate(errList)
}

func (oc *OvsController) validateServiceNetwork(networkCIDR string, hostIPNets []*net.IPNet) error {
	serviceIP, serviceIPNet, err := net.ParseCIDR(networkCIDR)
	if err != nil {
		return fmt.Errorf("Failed to parse network address: %s", networkCIDR)
	}

	errList := []error{}
	for _, ipNet := range hostIPNets {
		if ipNet.Contains(serviceIP) {
			errList = append(errList, fmt.Errorf("Error: Service IP: %s conflicts with host network: %s", ipNet.String(), networkCIDR))
		}
		if serviceIPNet.Contains(ipNet.IP) {
			errList = append(errList, fmt.Errorf("Error: Host network with IP: %s conflicts with service network: %s", ipNet.IP.String(), networkCIDR))
		}
	}

	services, _, err := oc.Registry.GetServices()
	if err != nil {
		return err
	}
	for _, svc := range services {
		if !serviceIPNet.Contains(net.ParseIP(svc.IP)) {
			errList = append(errList, fmt.Errorf("Error: Existing service with IP: %s is not part of service network: %s", svc.IP, networkCIDR))
		}
	}
	return kerrors.NewAggregate(errList)
}

func (oc *OvsController) validateNetworkConfig(clusterNetworkCIDR, serviceNetworkCIDR string, subnetsInUse []string) error {
	// TODO: Instead of hardcoding 'tun0' and 'lbr0', get it from common place.
	// This will ensure both the kube/multitenant scripts and master validations use the same name.
	hostIPNets, err := netutils.GetHostIPNetworks([]string{"tun0", "lbr0"})
	if err != nil {
		return err
	}

	errList := []error{}
	if err := oc.validateClusterNetwork(clusterNetworkCIDR, subnetsInUse, hostIPNets); err != nil {
		errList = append(errList, err)
	}
	if err := oc.validateServiceNetwork(serviceNetworkCIDR, hostIPNets); err != nil {
		errList = append(errList, err)
	}
	return kerrors.NewAggregate(errList)
}

func (oc *OvsController) StartMaster(clusterNetworkCIDR string, clusterBitsPerSubnet uint, serviceNetworkCIDR string) error {
	// Any mismatch in cluster/service network is handled by WriteNetworkConfig
	// For any new cluster/service network, ensure existing node subnets belong
	// to the given cluster network and service IPs belong to the given service network
	if _, err := oc.Registry.GetClusterNetworkCIDR(); err != nil {
		subrange := make([]string, 0)
		subnets, _, err := oc.Registry.GetSubnets()
		if err != nil {
			log.Errorf("Error in initializing/fetching subnets: %v", err)
			return err
		}
		for _, sub := range subnets {
			subrange = append(subrange, sub.SubnetCIDR)
		}

		err = oc.validateNetworkConfig(clusterNetworkCIDR, serviceNetworkCIDR, subrange)
		if err != nil {
			return err
		}
	}

	if err := oc.Registry.WriteNetworkConfig(clusterNetworkCIDR, clusterBitsPerSubnet, serviceNetworkCIDR); err != nil {
		return err
	}

	if err := oc.pluginHooks.PluginStartMaster(clusterNetworkCIDR, clusterBitsPerSubnet, serviceNetworkCIDR); err != nil {
		return fmt.Errorf("Failed to start plugin: %v", err)
	}

	return nil
}

func (oc *OvsController) StartNode(mtu uint) error {
	// Assume we are working with IPv4
	clusterNetworkCIDR, err := oc.Registry.GetClusterNetworkCIDR()
	if err != nil {
		log.Errorf("Failed to obtain ClusterNetwork: %v", err)
		return err
	}

	ipt := iptables.New(kexec.New(), utildbus.New(), iptables.ProtocolIpv4)
	if err := SetupIptables(ipt, clusterNetworkCIDR); err != nil {
		return fmt.Errorf("Failed to set up iptables: %v", err)
	}

	ipt.AddReloadFunc(func() {
		err := SetupIptables(ipt, clusterNetworkCIDR)
		if err != nil {
			log.Errorf("Error reloading iptables: %v\n", err)
		}
	})

	if err := oc.pluginHooks.PluginStartNode(mtu); err != nil {
		return fmt.Errorf("Failed to start plugin: %v", err)
	}

	oc.markPodNetworkReady()

	return nil
}

func (oc *OvsController) markPodNetworkReady() {
	close(oc.podNetworkReady)
}

func (oc *OvsController) WaitForPodNetworkReady() error {
	logInterval := 10 * time.Second
	numIntervals := 12 // timeout: 2 mins

	for i := 0; i < numIntervals; i++ {
		select {
		// Wait for StartNode() to finish SDN setup
		case <-oc.podNetworkReady:
			return nil
		case <-time.After(logInterval):
			log.Infof("Waiting for SDN pod network to be ready...")
		}
	}
	return fmt.Errorf("SDN pod network is not ready(timeout: 2 mins)")
}

func (oc *OvsController) Stop() {
	close(oc.sig)
}

// Wait for ready signal from Watch interface for the given resource
// Closes the ready channel as we don't need it anymore after this point
func waitForWatchReadiness(ready chan bool, resourceName string) {
	timeout := time.Minute
	select {
	case <-ready:
		close(ready)
	case <-time.After(timeout):
		log.Fatalf("Watch for resource %s is not ready(timeout: %v)", resourceName, timeout)
	}
	return
}

type watchWatcher func(oc *OvsController, ready chan<- bool, start <-chan string)
type watchGetter func(registry *Registry) (interface{}, string, error)

// watchAndGetResource will fetch current items in etcd and watch for any new
// changes for the given resource.
// Supported resources: nodes, subnets, namespaces, services, netnamespaces, and pods.
//
// To avoid any potential race conditions during this process, these steps are followed:
// 1. Initiator(master/node): Watch for a resource as an async op, lets say WatchProcess
// 2. WatchProcess: When ready for watching, send ready signal to initiator
// 3. Initiator: Wait for watch resource to be ready
//    This is needed as step-1 is an asynchronous operation
// 4. WatchProcess: Collect new changes in the queue but wait for initiator
//    to indicate which version to start from
// 5. Initiator: Get existing items with their latest version for the resource
// 6. Initiator: Send version from step-5 to WatchProcess
// 7. WatchProcess: Ignore any items with version <= start version got from initiator on step-6
// 8. WatchProcess: Handle new changes
func (oc *OvsController) watchAndGetResource(resourceName string, watcher watchWatcher, getter watchGetter) (interface{}, error) {
	ready := make(chan bool)
	start := make(chan string)

	go watcher(oc, ready, start)
	waitForWatchReadiness(ready, strings.ToLower(resourceName))
	getOutput, version, err := getter(oc.Registry)
	if err != nil {
		return nil, err
	}

	start <- version

	return getOutput, nil
}

type FirewallRule struct {
	table string
	chain string
	args  []string
}

func SetupIptables(ipt iptables.Interface, clusterNetworkCIDR string) error {
	rules := []FirewallRule{
		{"nat", "POSTROUTING", []string{"-s", clusterNetworkCIDR, "!", "-d", clusterNetworkCIDR, "-j", "MASQUERADE"}},
		{"filter", "INPUT", []string{"-p", "udp", "-m", "multiport", "--dports", "4789", "-m", "comment", "--comment", "001 vxlan incoming", "-j", "ACCEPT"}},
		{"filter", "INPUT", []string{"-i", "tun0", "-m", "comment", "--comment", "traffic from docker for internet", "-j", "ACCEPT"}},
		{"filter", "FORWARD", []string{"-d", clusterNetworkCIDR, "-j", "ACCEPT"}},
		{"filter", "FORWARD", []string{"-s", clusterNetworkCIDR, "-j", "ACCEPT"}},
	}

	for _, rule := range rules {
		_, err := ipt.EnsureRule(iptables.Prepend, iptables.Table(rule.table), iptables.Chain(rule.chain), rule.args...)
		if err != nil {
			return err
		}
	}

	return nil
}
<commit_msg>If NodeIP and NodeName are unsuitable, fallback to default interface IP address<commit_after>package osdn

import (
	"fmt"
	"net"
	"strings"
	"time"

	log "github.com/golang/glog"

	"github.com/openshift/openshift-sdn/pkg/netutils"
	"github.com/openshift/openshift-sdn/plugins/osdn/api"

	kubetypes "k8s.io/kubernetes/pkg/kubelet/types"
	kubeutil "k8s.io/kubernetes/pkg/util"
	utildbus "k8s.io/kubernetes/pkg/util/dbus"
	kerrors "k8s.io/kubernetes/pkg/util/errors"
	kexec "k8s.io/kubernetes/pkg/util/exec"
	"k8s.io/kubernetes/pkg/util/iptables"
)

type PluginHooks interface {
	PluginStartMaster(clusterNetworkCIDR string, clusterBitsPerSubnet uint, serviceNetworkCIDR string) error
	PluginStartNode(mtu uint) error
	UpdatePod(namespace string, name string, id kubetypes.DockerID) error
}

type OvsController struct {
	pluginHooks     PluginHooks
	Registry        *Registry
	localIP         string
	localSubnet     *api.Subnet
	hostName        string
	subnetAllocator *netutils.SubnetAllocator
	sig             chan struct{}
	podNetworkReady chan struct{}
	flowController  FlowController
	VNIDMap         map[string]uint
	netIDManager    *netutils.NetIDAllocator
	adminNamespaces []string
	services        map[string]api.Service
}

type FlowController interface {
	Setup(localSubnetCIDR, clusterNetworkCIDR, serviceNetworkCIDR string, mtu uint) error

	AddOFRules(nodeIP, nodeSubnetCIDR, localIP string) error
	DelOFRules(nodeIP, localIP string) error

	AddServiceOFRules(netID uint, IP string, protocol api.ServiceProtocol, port uint) error
	DelServiceOFRules(netID uint, IP string, protocol api.ServiceProtocol, port uint) error
}

// Called by plug factory functions to initialize the generic plugin instance
func (oc *OvsController) BaseInit(registry *Registry, flowController FlowController, pluginHooks PluginHooks, hostname string, selfIP string) error {

	if hostname == "" {
		output, err := kexec.New().Command("uname", "-n").CombinedOutput()
		if err != nil {
			return err
		}
		hostname = strings.TrimSpace(string(output))
	}

	if selfIP == "" {
		var err error
		selfIP, err = netutils.GetNodeIP(hostname)
		if err != nil {
			log.V(5).Infof("Failed to determine node address from hostname %s; using default interface (%v)", hostname, err)
			defaultIP, err := kubeutil.ChooseHostInterface()
			if err != nil {
				return err
			}
			selfIP = defaultIP.String()
		}
	}
	log.Infof("Self IP: %s.", selfIP)

	oc.pluginHooks = pluginHooks
	oc.Registry = registry
	oc.flowController = flowController
	oc.localIP = selfIP
	oc.hostName = hostname
	oc.VNIDMap = make(map[string]uint)
	oc.sig = make(chan struct{})
	oc.podNetworkReady = make(chan struct{})
	oc.adminNamespaces = make([]string, 0)
	oc.services = make(map[string]api.Service)

	return nil
}

func (oc *OvsController) validateClusterNetwork(networkCIDR string, subnetsInUse []string, hostIPNets []*net.IPNet) error {
	clusterIP, clusterIPNet, err := net.ParseCIDR(networkCIDR)
	if err != nil {
		return fmt.Errorf("Failed to parse network address: %s", networkCIDR)
	}

	errList := []error{}
	for _, ipNet := range hostIPNets {
		if ipNet.Contains(clusterIP) {
			errList = append(errList, fmt.Errorf("Error: Cluster IP: %s conflicts with host network: %s", clusterIP.String(), ipNet.String()))
		}
		if clusterIPNet.Contains(ipNet.IP) {
			errList = append(errList, fmt.Errorf("Error: Host network with IP: %s conflicts with cluster network: %s", ipNet.IP.String(), networkCIDR))
		}
	}

	for _, netStr := range subnetsInUse {
		subnetIP, _, err := net.ParseCIDR(netStr)
		if err != nil {
			errList = append(errList, fmt.Errorf("Failed to parse network address: %s", netStr))
			continue
		}
		if !clusterIPNet.Contains(subnetIP) {
			errList = append(errList, fmt.Errorf("Error: Existing node subnet: %s is not part of cluster network: %s", netStr, networkCIDR))
		}
	}
	return kerrors.NewAggregate(errList)
}

func (oc *OvsController) validateServiceNetwork(networkCIDR string, hostIPNets []*net.IPNet) error {
	serviceIP, serviceIPNet, err := net.ParseCIDR(networkCIDR)
	if err != nil {
		return fmt.Errorf("Failed to parse network address: %s", networkCIDR)
	}

	errList := []error{}
	for _, ipNet := range hostIPNets {
		if ipNet.Contains(serviceIP) {
			errList = append(errList, fmt.Errorf("Error: Service IP: %s conflicts with host network: %s", ipNet.String(), networkCIDR))
		}
		if serviceIPNet.Contains(ipNet.IP) {
			errList = append(errList, fmt.Errorf("Error: Host network with IP: %s conflicts with service network: %s", ipNet.IP.String(), networkCIDR))
		}
	}

	services, _, err := oc.Registry.GetServices()
	if err != nil {
		return err
	}
	for _, svc := range services {
		if !serviceIPNet.Contains(net.ParseIP(svc.IP)) {
			errList = append(errList, fmt.Errorf("Error: Existing service with IP: %s is not part of service network: %s", svc.IP, networkCIDR))
		}
	}
	return kerrors.NewAggregate(errList)
}

func (oc *OvsController) validateNetworkConfig(clusterNetworkCIDR, serviceNetworkCIDR string, subnetsInUse []string) error {
	// TODO: Instead of hardcoding 'tun0' and 'lbr0', get it from common place.
	// This will ensure both the kube/multitenant scripts and master validations use the same name.
	hostIPNets, err := netutils.GetHostIPNetworks([]string{"tun0", "lbr0"})
	if err != nil {
		return err
	}

	errList := []error{}
	if err := oc.validateClusterNetwork(clusterNetworkCIDR, subnetsInUse, hostIPNets); err != nil {
		errList = append(errList, err)
	}
	if err := oc.validateServiceNetwork(serviceNetworkCIDR, hostIPNets); err != nil {
		errList = append(errList, err)
	}
	return kerrors.NewAggregate(errList)
}

func (oc *OvsController) StartMaster(clusterNetworkCIDR string, clusterBitsPerSubnet uint, serviceNetworkCIDR string) error {
	// Any mismatch in cluster/service network is handled by WriteNetworkConfig
	// For any new cluster/service network, ensure existing node subnets belong
	// to the given cluster network and service IPs belong to the given service network
	if _, err := oc.Registry.GetClusterNetworkCIDR(); err != nil {
		subrange := make([]string, 0)
		subnets, _, err := oc.Registry.GetSubnets()
		if err != nil {
			log.Errorf("Error in initializing/fetching subnets: %v", err)
			return err
		}
		for _, sub := range subnets {
			subrange = append(subrange, sub.SubnetCIDR)
		}

		err = oc.validateNetworkConfig(clusterNetworkCIDR, serviceNetworkCIDR, subrange)
		if err != nil {
			return err
		}
	}

	if err := oc.Registry.WriteNetworkConfig(clusterNetworkCIDR, clusterBitsPerSubnet, serviceNetworkCIDR); err != nil {
		return err
	}

	if err := oc.pluginHooks.PluginStartMaster(clusterNetworkCIDR, clusterBitsPerSubnet, serviceNetworkCIDR); err != nil {
		return fmt.Errorf("Failed to start plugin: %v", err)
	}

	return nil
}

func (oc *OvsController) StartNode(mtu uint) error {
	// Assume we are working with IPv4
	clusterNetworkCIDR, err := oc.Registry.GetClusterNetworkCIDR()
	if err != nil {
		log.Errorf("Failed to obtain ClusterNetwork: %v", err)
		return err
	}

	ipt := iptables.New(kexec.New(), utildbus.New(), iptables.ProtocolIpv4)
	if err := SetupIptables(ipt, clusterNetworkCIDR); err != nil {
		return fmt.Errorf("Failed to set up iptables: %v", err)
	}

	ipt.AddReloadFunc(func() {
		err := SetupIptables(ipt, clusterNetworkCIDR)
		if err != nil {
			log.Errorf("Error reloading iptables: %v\n", err)
		}
	})

	if err := oc.pluginHooks.PluginStartNode(mtu); err != nil {
		return fmt.Errorf("Failed to start plugin: %v", err)
	}

	oc.markPodNetworkReady()

	return nil
}

func (oc *OvsController) markPodNetworkReady() {
	close(oc.podNetworkReady)
}

func (oc *OvsController) WaitForPodNetworkReady() error {
	logInterval := 10 * time.Second
	numIntervals := 12 // timeout: 2 mins

	for i := 0; i < numIntervals; i++ {
		select {
		// Wait for StartNode() to finish SDN setup
		case <-oc.podNetworkReady:
			return nil
		case <-time.After(logInterval):
			log.Infof("Waiting for SDN pod network to be ready...")
		}
	}
	return fmt.Errorf("SDN pod network is not ready(timeout: 2 mins)")
}

func (oc *OvsController) Stop() {
	close(oc.sig)
}

// Wait for ready signal from Watch interface for the given resource
// Closes the ready channel as we don't need it anymore after this point
func waitForWatchReadiness(ready chan bool, resourceName string) {
	timeout := time.Minute
	select {
	case <-ready:
		close(ready)
	case <-time.After(timeout):
		log.Fatalf("Watch for resource %s is not ready(timeout: %v)", resourceName, timeout)
	}
	return
}

type watchWatcher func(oc *OvsController, ready chan<- bool, start <-chan string)
type watchGetter func(registry *Registry) (interface{}, string, error)

// watchAndGetResource will fetch current items in etcd and watch for any new
// changes for the given resource.
// Supported resources: nodes, subnets, namespaces, services, netnamespaces, and pods.
//
// To avoid any potential race conditions during this process, these steps are followed:
// 1. Initiator(master/node): Watch for a resource as an async op, lets say WatchProcess
// 2. WatchProcess: When ready for watching, send ready signal to initiator
// 3. Initiator: Wait for watch resource to be ready
//    This is needed as step-1 is an asynchronous operation
// 4. WatchProcess: Collect new changes in the queue but wait for initiator
//    to indicate which version to start from
// 5. Initiator: Get existing items with their latest version for the resource
// 6. Initiator: Send version from step-5 to WatchProcess
// 7. WatchProcess: Ignore any items with version <= start version got from initiator on step-6
// 8. WatchProcess: Handle new changes
func (oc *OvsController) watchAndGetResource(resourceName string, watcher watchWatcher, getter watchGetter) (interface{}, error) {
	ready := make(chan bool)
	start := make(chan string)

	go watcher(oc, ready, start)
	waitForWatchReadiness(ready, strings.ToLower(resourceName))
	getOutput, version, err := getter(oc.Registry)
	if err != nil {
		return nil, err
	}

	start <- version

	return getOutput, nil
}

type FirewallRule struct {
	table string
	chain string
	args  []string
}

func SetupIptables(ipt iptables.Interface, clusterNetworkCIDR string) error {
	rules := []FirewallRule{
		{"nat", "POSTROUTING", []string{"-s", clusterNetworkCIDR, "!", "-d", clusterNetworkCIDR, "-j", "MASQUERADE"}},
		{"filter", "INPUT", []string{"-p", "udp", "-m", "multiport", "--dports", "4789", "-m", "comment", "--comment", "001 vxlan incoming", "-j", "ACCEPT"}},
		{"filter", "INPUT", []string{"-i", "tun0", "-m", "comment", "--comment", "traffic from docker for internet", "-j", "ACCEPT"}},
		{"filter", "FORWARD", []string{"-d", clusterNetworkCIDR, "-j", "ACCEPT"}},
		{"filter", "FORWARD", []string{"-s", clusterNetworkCIDR, "-j", "ACCEPT"}},
	}

	for _, rule := range rules {
		_, err := ipt.EnsureRule(iptables.Prepend, iptables.Table(rule.table), iptables.Chain(rule.chain), rule.args...)
		if err != nil {
			return err
		}
	}

	return nil
}
<|endoftext|>


<commit_before>package ligno

import (
	"runtime"
	"sync"
	"sync/atomic"
	"time"
)

type tracker struct {
	loggers       []*Logger
	loggerCreated chan *Logger
	mu            sync.RWMutex
}

func (lt *tracker) run() {
	for l := range lt.loggerCreated {
		lt.mu.Lock()
		lt.loggers = append(lt.loggers, l)
		lt.mu.Unlock()
	}
}

func (lt *tracker) wait(done chan struct{}) {
	lt.mu.RLock()
	defer lt.mu.RUnlock()
	var wg sync.WaitGroup
	for _, l := range lt.loggers {
		wg.Add(1)
		go func(l *Logger) {
			l.Wait()
			wg.Done()
		}(l)
	}
	wg.Wait()
	close(done)
}

var loggerTracker = tracker{
	loggers:       make([]*Logger, 0, 8),
	loggerCreated: make(chan *Logger),
}

var defaultLog *Logger

func init() {
	go loggerTracker.run()
	// done here instead of in default to make sure that tracker is
	// running before creating any loggers
	defaultLog = New(nil, []Handler{stdoutHandler})
}

// WaitAll blocks until all loggers are finished with message processing.
func WaitAll() {
	done := make(chan struct{})
	loggerTracker.wait(done)
	<-done
}

// WaitAllTimeout blocks until all messages send to all loggers are processed or max
// specified amount of time.
// Boolean return value indicates if function returned because all messages
// were processed (true) or because timeout has expired (false).
func WaitAllTimeout(t time.Duration) bool {
	done := make(chan struct{})
	timeout := time.After(t)
	go loggerTracker.wait(done)
	select {
	case <-done:
		return true
	case <-timeout:
		return false
	}
}

// Logger is central data type in ligno which represents logger itself.
// Logger is first level of processing events. It creates them and
// queues for async processing. It holds slice of Handlers that process
// messages and context (set of key-value pairs that will be include
// in every log record).
type Logger struct {
	// Context in which logger is operating. Basically, this is set of
	// key-value pairs that will be added to every record logged with this
	// logger. They have lowest priority.
	Context Record
	// Handlers is slice of handlers for processing messages.
	Handlers []Handler
	// Parent is logger that this logger was created from.
	// It is used to create hierarchy of Context values.
	Parent *Logger
	// rawMessages is channel for queueing and buffering raw messages from
	// application which needs to be merged with context and submitted
	// to final processing
	rawRecords chan Record
	// records is channel for queueing and buffering log records.
	records chan Record
	// propagate is flag that determines if records will be propagated to
	// parent logger for processing too.
	propagate bool
	// notifyFinished is channel of channels. When someone wants to be notified
	// when logger processed all queued records, it sends channel that will be
	// closed after last queued record is processed to notifyFinished.
	notifyFinished chan chan struct{}
	// toProcess is number of messages left to process in this logger.
	toProcess int32
}

// New creates new instance of logger and starts it so it is ready for processing.
func New(context Record, handlers []Handler) *Logger {
	l := &Logger{
		Context:        context,
		Handlers:       handlers,
		records:        make(chan Record, 2048),
		rawRecords:     make(chan Record, 2048),
		notifyFinished: make(chan chan struct{}),
	}
	go l.handle()
	go l.processRecords()
	loggerTracker.loggerCreated <- l
	return l
}

// SubLogger creates and returns new logger whose parent is current logger.
func (l *Logger) SubLogger(context Record, handlers []Handler, propagate bool) *Logger {
	newLogger := New(context, handlers)
	newLogger.Parent = l
	newLogger.propagate = propagate
	return newLogger
}

// handle is log record processor which takes records from chan and invokes all handlers.
func (l *Logger) handle() {
	var handlers []Handler
	if len(l.Handlers) == 0 {
		handlers = []Handler{stdoutHandler}
	} else {
		handlers = l.Handlers
	}

	var notifyFinished chan struct{}
	for {
		select {
		case record := <- l.records:
			for _, h := range handlers {
				h.Handle(record)
			}
			atomic.AddInt32(&l.toProcess, -1)
			// if count dropped to 0, close notification channel
			if atomic.LoadInt32(&l.toProcess) == 0 && notifyFinished != nil {
				close(notifyFinished)
				// reset notification channel
				notifyFinished = nil
			}
		case notifyFinished = <-l.notifyFinished:
			// check count right away and notify that processing is done if possible
			if atomic.LoadInt32(&l.toProcess) == 0 {
				close(notifyFinished)
				// reset notification channel
				notifyFinished = nil
			}
		}
	}
}

// wait blocks until all messages on messages channel are processed.
// Provided done channel will be closed when messages are processed to notify
// interested parties that they can unblock.
func (l *Logger) wait(done chan struct{}) {
	runtime.Gosched()
	l.notifyFinished <- done
}

// Wait block until all messages sent to logger are processed.
// If timeout is needed, see WaitTimeout.
func (l *Logger) Wait() {
	done := make(chan struct{})
	l.wait(done)
	<-done
}

// WaitTimeout blocks until all messages send to logger are processed or max
// specified amount of time.
// Boolean return value indicates if function returned because all messages
// were processed (true) or because timeout has expired (false).
func (l *Logger) WaitTimeout(t time.Duration) (ok bool) {
	done := make(chan struct{})
	timeout := time.After(t)
	l.wait(done)
	select {
	case <-done:
		return true
	case <-timeout:
		return false
	}
}

// log creates record suitable for processing and sends it to messages chan.
func (l *Logger) log(data Record) {
	for k, v := range l.Context {
		data[k] = v
	}
	if _, ok := data[TimeKey]; !ok {
		data[TimeKey] = time.Now().UTC()
	}
	atomic.AddInt32(&l.toProcess, 1)
	l.rawRecords <- data
}

func (l *Logger) processRecords() {
	for data := range l.rawRecords {
		var current = l
		var loggerChain = make([]*Logger, 0, 5)

		// create list of all parents
		for current != nil {
			loggerChain = append(loggerChain, current)
			current = current.Parent
		}
		// merge context of all parents backwards, because children can override parents
		mergedData := make(Record)
		for i := len(loggerChain) - 1; i >= 0; i-- {
			for k, v := range loggerChain[i].Context {
				mergedData[k] = v
			}
		}
		// finally, add provided data
		for k, v := range data {
			mergedData[k] = v
		}
		l.records <- mergedData
		if l.propagate && l.Parent != nil {
			l.Parent.log(data)
		}
	}
}

// Log creates record and queues it for processing.
// Required parameters are level for record and event that occurred. Any
// additional parameters will be transformed to key-value pairs for record
// in order in which they were provided. There should be even number of them,
// but in case that there is on number of parameters, empty string is
// appended. Example:
//   l.Log(INFO, "User logged in", "user_id", user_id, "platform", PLATFORM_NAME)
// will be translated into log record with following keys:
//  {LEVEL: INFO", EVENT: "User logged in", "user_id": user_id, "platform": PLATFORM_NAME}
func (l *Logger) Log(level Level, event string, pairs ...string) {
	var d = make(Record)
	d[EventKey] = event
	d[LevelKey] = level
	// make sure that number of items in data is even
	if len(pairs)%2 != 0 {
		pairs = append(pairs, "")
	}
	for i := 0; i < len(pairs); i += 2 {
		d[pairs[i]] = pairs[i+1]
	}
	l.log(d)
}

// LogRecord adds provided record to queue for processing.
func (l *Logger) LogRecord(record Record) {
	l.log(record)
}

// Debug creates log record and queues it for processing with DEBUG level.
// Additional parameters have same semantics as in Log method.
func (l *Logger) Debug(event string, pairs ...string) {
	l.Log(DEBUG, event, pairs...)
}

// DebugRecord adds DEBUG level to provided record and queues it for processing.
func (l *Logger) DebugRecord(record Record) {
	record[LevelKey] = DEBUG
	l.LogRecord(record)
}

// Info creates log record and queues it for processing with INFO level.
// Additional parameters have same semantics as in Log method.
func (l *Logger) Info(event string, pairs ...string) {
	l.Log(INFO, event, pairs...)
}

// InfoRecord adds INFO level to provided record and queues it for processing.
func (l *Logger) InfoRecord(record Record) {
	record[LevelKey] = INFO
	l.LogRecord(record)
}

// Warning creates log record and queues it for processing with WARNING level.
// Additional parameters have same semantics as in Log method.
func (l *Logger) Warning(event string, pairs ...string) {
	l.Log(WARNING, event, pairs...)
}

// WarningRecord adds WARNING level to provided record and queues it for processing.
func (l *Logger) WarningRecord(record Record) {
	record[LevelKey] = WARNING
	l.LogRecord(record)
}

// Error creates log record and queues it for processing with ERROR level.
// Additional parameters have same semantics as in Log method.
func (l *Logger) Error(event string, pairs ...string) {
	l.Log(ERROR, event, pairs...)
}

// ErrorRecord adds ERROR level to provided record and queues it for processing.
func (l *Logger) ErrorRecord(record Record) {
	record[LevelKey] = ERROR
	l.LogRecord(record)
}

// Critical creates log record and queues it for processing with CRITICAL level.
// Additional parameters have same semantics as in Log method.
func (l *Logger) Critical(event string, pairs ...string) {
	l.Log(CRITICAL, event, pairs...)
}

// CriticalRecord adds CRITICAL level to provided record and queues it for processing.
func (l *Logger) CriticalRecord(record Record) {
	record[LevelKey] = INFO
	l.LogRecord(record)
}
<commit_msg>Remove duplicated code for mergeing contexts<commit_after>package ligno

import (
	"runtime"
	"sync"
	"sync/atomic"
	"time"
)

type tracker struct {
	loggers       []*Logger
	loggerCreated chan *Logger
	mu            sync.RWMutex
}

func (lt *tracker) run() {
	for l := range lt.loggerCreated {
		lt.mu.Lock()
		lt.loggers = append(lt.loggers, l)
		lt.mu.Unlock()
	}
}

func (lt *tracker) wait(done chan struct{}) {
	lt.mu.RLock()
	defer lt.mu.RUnlock()
	var wg sync.WaitGroup
	for _, l := range lt.loggers {
		wg.Add(1)
		go func(l *Logger) {
			l.Wait()
			wg.Done()
		}(l)
	}
	wg.Wait()
	close(done)
}

var loggerTracker = tracker{
	loggers:       make([]*Logger, 0, 8),
	loggerCreated: make(chan *Logger),
}

var defaultLog *Logger

func init() {
	go loggerTracker.run()
	// done here instead of in default to make sure that tracker is
	// running before creating any loggers
	defaultLog = New(nil, []Handler{stdoutHandler})
}

// WaitAll blocks until all loggers are finished with message processing.
func WaitAll() {
	done := make(chan struct{})
	loggerTracker.wait(done)
	<-done
}

// WaitAllTimeout blocks until all messages send to all loggers are processed or max
// specified amount of time.
// Boolean return value indicates if function returned because all messages
// were processed (true) or because timeout has expired (false).
func WaitAllTimeout(t time.Duration) bool {
	done := make(chan struct{})
	timeout := time.After(t)
	go loggerTracker.wait(done)
	select {
	case <-done:
		return true
	case <-timeout:
		return false
	}
}

// Logger is central data type in ligno which represents logger itself.
// Logger is first level of processing events. It creates them and
// queues for async processing. It holds slice of Handlers that process
// messages and context (set of key-value pairs that will be include
// in every log record).
type Logger struct {
	// Context in which logger is operating. Basically, this is set of
	// key-value pairs that will be added to every record logged with this
	// logger. They have lowest priority.
	Context Record
	// Handlers is slice of handlers for processing messages.
	Handlers []Handler
	// Parent is logger that this logger was created from.
	// It is used to create hierarchy of Context values.
	Parent *Logger
	// rawMessages is channel for queueing and buffering raw messages from
	// application which needs to be merged with context and submitted
	// to final processing
	rawRecords chan Record
	// records is channel for queueing and buffering log records.
	records chan Record
	// propagate is flag that determines if records will be propagated to
	// parent logger for processing too.
	propagate bool
	// notifyFinished is channel of channels. When someone wants to be notified
	// when logger processed all queued records, it sends channel that will be
	// closed after last queued record is processed to notifyFinished.
	notifyFinished chan chan struct{}
	// toProcess is number of messages left to process in this logger.
	toProcess int32
}

// New creates new instance of logger and starts it so it is ready for processing.
func New(context Record, handlers []Handler) *Logger {
	l := &Logger{
		Context:        context,
		Handlers:       handlers,
		records:        make(chan Record, 2048),
		rawRecords:     make(chan Record, 2048),
		notifyFinished: make(chan chan struct{}),
	}
	go l.handle()
	go l.processRecords()
	loggerTracker.loggerCreated <- l
	return l
}

// SubLogger creates and returns new logger whose parent is current logger.
func (l *Logger) SubLogger(context Record, handlers []Handler, propagate bool) *Logger {
	newLogger := New(context, handlers)
	newLogger.Parent = l
	newLogger.propagate = propagate
	return newLogger
}

// handle is log record processor which takes records from chan and invokes all handlers.
func (l *Logger) handle() {
	var handlers []Handler
	if len(l.Handlers) == 0 {
		handlers = []Handler{stdoutHandler}
	} else {
		handlers = l.Handlers
	}

	var notifyFinished chan struct{}
	for {
		select {
		case record := <-l.records:
			for _, h := range handlers {
				h.Handle(record)
			}
			atomic.AddInt32(&l.toProcess, -1)
			// if count dropped to 0, close notification channel
			if atomic.LoadInt32(&l.toProcess) == 0 && notifyFinished != nil {
				close(notifyFinished)
				// reset notification channel
				notifyFinished = nil
			}
		case notifyFinished = <-l.notifyFinished:
			// check count right away and notify that processing is done if possible
			if atomic.LoadInt32(&l.toProcess) == 0 {
				close(notifyFinished)
				// reset notification channel
				notifyFinished = nil
			}
		}
	}
}

// processRecords creates full records from provided user record and this and
// all parents contexts.
func (l *Logger) processRecords() {
	for data := range l.rawRecords {
		var current = l
		var loggerChain = make([]*Logger, 0, 5)

		// create list of all parents
		for current != nil {
			loggerChain = append(loggerChain, current)
			current = current.Parent
		}
		// merge context of all parents backwards, because children can override parents
		mergedData := make(Record)
		for i := len(loggerChain) - 1; i >= 0; i-- {
			for k, v := range loggerChain[i].Context {
				mergedData[k] = v
			}
		}
		// finally, add provided data to override all context keys
		for k, v := range data {
			mergedData[k] = v
		}
		l.records <- mergedData
		if l.propagate && l.Parent != nil {
			l.Parent.log(data)
		}
	}
}

// log creates record suitable for processing and sends it to messages chan.
func (l *Logger) log(data Record) {
	if _, ok := data[TimeKey]; !ok {
		data[TimeKey] = time.Now().UTC()
	}
	atomic.AddInt32(&l.toProcess, 1)
	l.rawRecords <- data
}

// wait blocks until all messages on messages channel are processed.
// Provided done channel will be closed when messages are processed to notify
// interested parties that they can unblock.
func (l *Logger) wait(done chan struct{}) {
	runtime.Gosched()
	l.notifyFinished <- done
}

// Wait block until all messages sent to logger are processed.
// If timeout is needed, see WaitTimeout.
func (l *Logger) Wait() {
	done := make(chan struct{})
	l.wait(done)
	<-done
}

// WaitTimeout blocks until all messages send to logger are processed or max
// specified amount of time.
// Boolean return value indicates if function returned because all messages
// were processed (true) or because timeout has expired (false).
func (l *Logger) WaitTimeout(t time.Duration) (ok bool) {
	done := make(chan struct{})
	timeout := time.After(t)
	l.wait(done)
	select {
	case <-done:
		return true
	case <-timeout:
		return false
	}
}

// Log creates record and queues it for processing.
// Required parameters are level for record and event that occurred. Any
// additional parameters will be transformed to key-value pairs for record
// in order in which they were provided. There should be even number of them,
// but in case that there is on number of parameters, empty string is
// appended. Example:
//   l.Log(INFO, "User logged in", "user_id", user_id, "platform", PLATFORM_NAME)
// will be translated into log record with following keys:
//  {LEVEL: INFO", EVENT: "User logged in", "user_id": user_id, "platform": PLATFORM_NAME}
func (l *Logger) Log(level Level, event string, pairs ...string) {
	var d = make(Record)
	d[EventKey] = event
	d[LevelKey] = level
	// make sure that number of items in data is even
	if len(pairs)%2 != 0 {
		pairs = append(pairs, "")
	}
	for i := 0; i < len(pairs); i += 2 {
		d[pairs[i]] = pairs[i+1]
	}
	l.log(d)
}

// LogRecord adds provided record to queue for processing.
func (l *Logger) LogRecord(record Record) {
	l.log(record)
}

// Debug creates log record and queues it for processing with DEBUG level.
// Additional parameters have same semantics as in Log method.
func (l *Logger) Debug(event string, pairs ...string) {
	l.Log(DEBUG, event, pairs...)
}

// DebugRecord adds DEBUG level to provided record and queues it for processing.
func (l *Logger) DebugRecord(record Record) {
	record[LevelKey] = DEBUG
	l.LogRecord(record)
}

// Info creates log record and queues it for processing with INFO level.
// Additional parameters have same semantics as in Log method.
func (l *Logger) Info(event string, pairs ...string) {
	l.Log(INFO, event, pairs...)
}

// InfoRecord adds INFO level to provided record and queues it for processing.
func (l *Logger) InfoRecord(record Record) {
	record[LevelKey] = INFO
	l.LogRecord(record)
}

// Warning creates log record and queues it for processing with WARNING level.
// Additional parameters have same semantics as in Log method.
func (l *Logger) Warning(event string, pairs ...string) {
	l.Log(WARNING, event, pairs...)
}

// WarningRecord adds WARNING level to provided record and queues it for processing.
func (l *Logger) WarningRecord(record Record) {
	record[LevelKey] = WARNING
	l.LogRecord(record)
}

// Error creates log record and queues it for processing with ERROR level.
// Additional parameters have same semantics as in Log method.
func (l *Logger) Error(event string, pairs ...string) {
	l.Log(ERROR, event, pairs...)
}

// ErrorRecord adds ERROR level to provided record and queues it for processing.
func (l *Logger) ErrorRecord(record Record) {
	record[LevelKey] = ERROR
	l.LogRecord(record)
}

// Critical creates log record and queues it for processing with CRITICAL level.
// Additional parameters have same semantics as in Log method.
func (l *Logger) Critical(event string, pairs ...string) {
	l.Log(CRITICAL, event, pairs...)
}

// CriticalRecord adds CRITICAL level to provided record and queues it for processing.
func (l *Logger) CriticalRecord(record Record) {
	record[LevelKey] = INFO
	l.LogRecord(record)
}
<|endoftext|>


<commit_before>/*
 * Copyright 2014 Xuyuan Pang <xuyuanp@gmail.com>
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package glogger

import (
	"fmt"
	"runtime"
	"time"
)

type LogLevel uint8

const (
	DebugLevel LogLevel = iota
	InfoLevel
	WarnLevel
	ErrorLevel
	CriticalLevel
)

type Logger struct {
	GroupFilter
	GroupHandler
	Name   string
	Level  LogLevel
	Parent *Logger
}

func New(name string, level LogLevel) *Logger {
	l := &Logger{
		Name:  name,
		Level: level,
	}
	registerLogger(l)
	return l
}

func (l *Logger) log(level LogLevel, msg string) {
	if level < l.Level {
		return
	}
	now := time.Now()
	pc, file, line, ok := runtime.Caller(2)
	f := runtime.FuncForPC(pc)
	if !ok {
		file = "???"
		line = 0
	}
	rec := NewRecord(l.Name, now, level, file, f.Name(), line, msg)
	if !l.DoFilter(rec) {
		return
	}
	l.Handle(rec)
}

func (l *Logger) Info(f string, v ...interface{}) {
	l.log(InfoLevel, fmt.Sprintf(f, v...))
}

func (l *Logger) Debug(f string, v ...interface{}) {
	l.log(DebugLevel, fmt.Sprintf(f, v...))
}

func (l *Logger) Warning(f string, v ...interface{}) {
	l.log(WarnLevel, fmt.Sprintf(f, v...))
}

func (l *Logger) Error(f string, v ...interface{}) {
	l.log(ErrorLevel, fmt.Sprintf(f, v...))
}

func (l *Logger) Critical(f string, v ...interface{}) {
	l.log(CriticalLevel, fmt.Sprintf(f, v...))
}
<commit_msg>remove old logger<commit_after><|endoftext|>


<commit_before>// Copyright 2013, Cong Ding. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//   http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// author: Cong Ding <dinggnu@gmail.com>

// Package logging implements log library for other applications. It provides
// functions Debug, Info, Warning, Error, Critical, and formatting version
// Logf.
//
// Example:
//
//	logger := logging.SimpleLogger("main")
//	logger.SetLevel(logging.WARNING)
//	logger.Error("test for error")
//	logger.Warning("test for warning", "second parameter")
//	logger.Debug("test for debug")
//
package logging

import (
	"io"
	"os"
	"sync"
	"sync/atomic"
	"time"
)

// Pre-defined formats
const (
	DefaultFileName   = "logging.log"                   // default logging filename
	DefaultTimeFormat = "2006-01-02 15:04:05.999999999" // defaulttime format
	bufSize           = 1000                            // buffer size for writer
	queueSize         = 10000                           // chan queue size in async logging
	reqSize           = 10000                           // chan queue size in async logging
)

// Logger is the logging struct.
type Logger struct {

	// Be careful of the alignment issue of the variable seqid because it
	// uses the sync/atomic.AddUint64() operation. If the alignment is
	// wrong, it will cause a panic. To solve the alignment issue in an
	// easy way, we put seqid to the beginning of the structure.
	// seqid is only visiable internally.
	seqid uint64 // last used sequence number in record

	// These variables can be configured by users.
	name         string    // logger name
	level        Level     // record level higher than this will be printed
	recordFormat string    // format of the record
	recordArgs   []string  // arguments to be used in the recordFormat
	out          io.Writer // writer
	sync         bool      // use sync or async way to record logs
	timeFormat   string    // format for time

	// These variables are visible to users.
	startTime time.Time // start time of the logger

	// Internally used variables, which don't have get and set functions.
	wlock   sync.Mutex   // writer lock
	queue   chan string  // queue used in async logging
	request chan request // queue used in non-runtime logging
	flush   chan bool    // flush signal for the watcher to write
	quit    chan bool    // quit signal for the watcher to quit
	fd      *os.File     // file handler, used to close the file on destroy
	runtime bool         // with runtime operation or not
}

// request struct stores the logger request
type request struct {
	level  Level
	format string
	v      []interface{}
}

// SimpleLogger creates a new logger with simple configuration.
func SimpleLogger(name string) (*Logger, error) {
	return createLogger(name, WARNING, BasicFormat, DefaultTimeFormat, os.Stdout, false)
}

// BasicLogger creates a new logger with basic configuration.
func BasicLogger(name string) (*Logger, error) {
	return FileLogger(name, WARNING, BasicFormat, DefaultTimeFormat, DefaultFileName, false)
}

// RichLogger creates a new logger with simple configuration.
func RichLogger(name string) (*Logger, error) {
	return FileLogger(name, NOTSET, RichFormat, DefaultTimeFormat, DefaultFileName, false)
}

// FileLogger creates a new logger with file output.
func FileLogger(name string, level Level, format string, timeFormat string, file string, sync bool) (*Logger, error) {
	out, err := os.Create(file)
	if err != nil {
		return new(Logger), err
	}
	logger, err := createLogger(name, level, format, timeFormat, out, sync)
	if err == nil {
		logger.fd = out
	}
	return logger, err
}

func WriterLogger(name string, level Level, format string, timeFormat string, out io.Writer, sync bool) (*Logger, error) {
	return createLogger(name, level, format, timeFormat, out, sync)
}

// createLogger create a new logger
func createLogger(name string, level Level, format string, timeFormat string, out io.Writer, sync bool) (*Logger, error) {
	logger := new(Logger)

	err := logger.parseFormat(format)
	if err != nil {
		return logger, err
	}

	// asign values to logger
	logger.name = name
	logger.level = level
	logger.out = out
	logger.seqid = 0
	logger.sync = sync
	logger.queue = make(chan string, queueSize)
	logger.request = make(chan request, reqSize)
	logger.flush = make(chan bool)
	logger.quit = make(chan bool)
	logger.startTime = time.Now()
	logger.fd = nil
	logger.timeFormat = timeFormat

	// start watcher to write logs if it is async or no runtime field
	if !logger.sync {
		go logger.watcher()
	}

	return logger, nil
}

// Destroy sends quit signal to watcher and releases all the resources.
func (logger *Logger) Destroy() {
	if !logger.sync {
		// quit watcher
		logger.quit <- true
		// wait for watcher quit
		<-logger.quit
	}
	// clean up
	if logger.fd != nil {
		logger.fd.Close()
	}
}

// Flush the writer
func (logger *Logger) Flush() {
	if !logger.sync {
		// send flush signal
		logger.flush <- true
		// wait for flush finish
		<-logger.flush
	}
}

// Getter functions

func (logger *Logger) Name() string {
	return logger.name
}

func (logger *Logger) TimeFormat() string {
	return logger.timeFormat
}

func (logger *Logger) Level() Level {
	return Level(atomic.LoadInt32((*int32)(&logger.level)))
}

func (logger *Logger) RecordFormat() string {
	return logger.recordFormat
}

func (logger *Logger) RecordArgs() []string {
	return logger.recordArgs
}

func (logger *Logger) Writer() io.Writer {
	return logger.out
}

func (logger *Logger) Sync() bool {
	return logger.sync
}

// Setter functions

func (logger *Logger) SetLevel(level Level) {
	atomic.StoreInt32((*int32)(&logger.level), int32(level))
}

func (logger *Logger) SetWriter(out ...io.Writer) {
	logger.out = io.MultiWriter(out...)
}
<commit_msg>add interface for startTime<commit_after>// Copyright 2013, Cong Ding. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//   http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// author: Cong Ding <dinggnu@gmail.com>

// Package logging implements log library for other applications. It provides
// functions Debug, Info, Warning, Error, Critical, and formatting version
// Logf.
//
// Example:
//
//	logger := logging.SimpleLogger("main")
//	logger.SetLevel(logging.WARNING)
//	logger.Error("test for error")
//	logger.Warning("test for warning", "second parameter")
//	logger.Debug("test for debug")
//
package logging

import (
	"io"
	"os"
	"sync"
	"sync/atomic"
	"time"
)

// Pre-defined formats
const (
	DefaultFileName   = "logging.log"                   // default logging filename
	DefaultTimeFormat = "2006-01-02 15:04:05.999999999" // defaulttime format
	bufSize           = 1000                            // buffer size for writer
	queueSize         = 10000                           // chan queue size in async logging
	reqSize           = 10000                           // chan queue size in async logging
)

// Logger is the logging struct.
type Logger struct {

	// Be careful of the alignment issue of the variable seqid because it
	// uses the sync/atomic.AddUint64() operation. If the alignment is
	// wrong, it will cause a panic. To solve the alignment issue in an
	// easy way, we put seqid to the beginning of the structure.
	// seqid is only visiable internally.
	seqid uint64 // last used sequence number in record

	// These variables can be configured by users.
	name         string    // logger name
	level        Level     // record level higher than this will be printed
	recordFormat string    // format of the record
	recordArgs   []string  // arguments to be used in the recordFormat
	out          io.Writer // writer
	sync         bool      // use sync or async way to record logs
	timeFormat   string    // format for time

	// These variables are visible to users.
	startTime time.Time // start time of the logger

	// Internally used variables, which don't have get and set functions.
	wlock   sync.Mutex   // writer lock
	queue   chan string  // queue used in async logging
	request chan request // queue used in non-runtime logging
	flush   chan bool    // flush signal for the watcher to write
	quit    chan bool    // quit signal for the watcher to quit
	fd      *os.File     // file handler, used to close the file on destroy
	runtime bool         // with runtime operation or not
}

// request struct stores the logger request
type request struct {
	level  Level
	format string
	v      []interface{}
}

// SimpleLogger creates a new logger with simple configuration.
func SimpleLogger(name string) (*Logger, error) {
	return createLogger(name, WARNING, BasicFormat, DefaultTimeFormat, os.Stdout, false)
}

// BasicLogger creates a new logger with basic configuration.
func BasicLogger(name string) (*Logger, error) {
	return FileLogger(name, WARNING, BasicFormat, DefaultTimeFormat, DefaultFileName, false)
}

// RichLogger creates a new logger with simple configuration.
func RichLogger(name string) (*Logger, error) {
	return FileLogger(name, NOTSET, RichFormat, DefaultTimeFormat, DefaultFileName, false)
}

// FileLogger creates a new logger with file output.
func FileLogger(name string, level Level, format string, timeFormat string, file string, sync bool) (*Logger, error) {
	out, err := os.Create(file)
	if err != nil {
		return new(Logger), err
	}
	logger, err := createLogger(name, level, format, timeFormat, out, sync)
	if err == nil {
		logger.fd = out
	}
	return logger, err
}

func WriterLogger(name string, level Level, format string, timeFormat string, out io.Writer, sync bool) (*Logger, error) {
	return createLogger(name, level, format, timeFormat, out, sync)
}

// createLogger create a new logger
func createLogger(name string, level Level, format string, timeFormat string, out io.Writer, sync bool) (*Logger, error) {
	logger := new(Logger)

	err := logger.parseFormat(format)
	if err != nil {
		return logger, err
	}

	// asign values to logger
	logger.name = name
	logger.level = level
	logger.out = out
	logger.seqid = 0
	logger.sync = sync
	logger.queue = make(chan string, queueSize)
	logger.request = make(chan request, reqSize)
	logger.flush = make(chan bool)
	logger.quit = make(chan bool)
	logger.startTime = time.Now()
	logger.fd = nil
	logger.timeFormat = timeFormat

	// start watcher to write logs if it is async or no runtime field
	if !logger.sync {
		go logger.watcher()
	}

	return logger, nil
}

// Destroy sends quit signal to watcher and releases all the resources.
func (logger *Logger) Destroy() {
	if !logger.sync {
		// quit watcher
		logger.quit <- true
		// wait for watcher quit
		<-logger.quit
	}
	// clean up
	if logger.fd != nil {
		logger.fd.Close()
	}
}

// Flush the writer
func (logger *Logger) Flush() {
	if !logger.sync {
		// send flush signal
		logger.flush <- true
		// wait for flush finish
		<-logger.flush
	}
}

// Getter functions

func (logger *Logger) Name() string {
	return logger.name
}

func (logger *Logger) StartTime() int64 {
	return logger.startTime.UnixNano()
}

func (logger *Logger) TimeFormat() string {
	return logger.timeFormat
}

func (logger *Logger) Level() Level {
	return Level(atomic.LoadInt32((*int32)(&logger.level)))
}

func (logger *Logger) RecordFormat() string {
	return logger.recordFormat
}

func (logger *Logger) RecordArgs() []string {
	return logger.recordArgs
}

func (logger *Logger) Writer() io.Writer {
	return logger.out
}

func (logger *Logger) Sync() bool {
	return logger.sync
}

// Setter functions

func (logger *Logger) SetLevel(level Level) {
	atomic.StoreInt32((*int32)(&logger.level), int32(level))
}

func (logger *Logger) SetWriter(out ...io.Writer) {
	logger.out = io.MultiWriter(out...)
}
<|endoftext|>