<commit_before>package kasper

import (
	"fmt"
	stdlibLog "log"
	"os"

	"github.com/sirupsen/logrus"
)

var log = NewBasicLogger(false)

type Logger interface {
	Debug(...interface{})
	Debugf(string, ...interface{})

	Info(...interface{})
	Infof(string, ...interface{})

	Panic(...interface{})
	Panicf(string, ...interface{})
}

func NewJSONLogger(topicProcessorName string, containerID int, debug bool) Logger {
	return newLogrus(topicProcessorName, containerID, debug, &logrus.JSONFormatter{})
}

func NewTextLogger(topicProcessorName string, containerID int, debug bool) Logger {
	return newLogrus(topicProcessorName, containerID, debug, &logrus.TextFormatter{})
}

func newLogrus(topicProcessorName string, containerID int, debug bool, formatter logrus.Formatter) Logger {
	logger := logrus.New()
	logger.Formatter = formatter
	if debug {
		logger.Level = logrus.DebugLevel
	} else {
		logger.Level = logrus.InfoLevel
	}
	return logger.
		WithField("type", "kasper").
		WithField("topic_processor_name", topicProcessorName).
		WithField("container_id", containerID)
}

type stdlibLogger struct {
	log   *stdlibLog.Logger
	debug bool
}

func (l *stdlibLogger) Debug(vs ...interface{}) {
	if l.debug {
		vs = append([]interface{}{"DEBUG "}, vs...)
		l.log.Print(vs...)
	}
}

func (l *stdlibLogger) Debugf(format string, vs ...interface{}) {
	if l.debug {
		l.log.Printf(fmt.Sprintf("DEBUG %s", format), vs...)
	}
}

func (l *stdlibLogger) Info(vs ...interface{}) {
	vs = append([]interface{}{"INFO "}, vs...)
	l.log.Print(vs...)
}

func (l *stdlibLogger) Infof(format string, vs ...interface{}) {
	l.log.Printf(fmt.Sprintf("INFO %s", format), vs...)
}

func (l *stdlibLogger) Panic(vs ...interface{}) {
	vs = append([]interface{}{"PANIC "}, vs...)
	l.log.Panic(vs...)
}

func (l *stdlibLogger) Panicf(format string, vs ...interface{}) {
	l.log.Panicf(fmt.Sprintf("PANIC %s", format), vs...)
}

func NewBasicLogger(debug bool) Logger {
	return &stdlibLogger{stdlibLog.New(os.Stderr, "(KASPER) ", stdlibLog.LstdFlags), debug}
}

type noopLogger struct{}

func (noopLogger) Debug(...interface{})          {}
func (noopLogger) Debugf(string, ...interface{}) {}
func (noopLogger) Info(...interface{})           {}
func (noopLogger) Infof(string, ...interface{})  {}
func (noopLogger) Panic(...interface{})          { panic("panic") }
func (noopLogger) Panicf(string, ...interface{}) { panic("panic") }

func SetLogger(logger Logger) {
	log = logger
}
<commit_msg>add logger docstrings<commit_after>package kasper

import (
	"fmt"
	stdlibLog "log"
	"os"

	"github.com/sirupsen/logrus"
)

var log = NewBasicLogger(false)

// Logger is a logging interface for Kasper
type Logger interface {
	Debug(...interface{})
	Debugf(string, ...interface{})

	Info(...interface{})
	Infof(string, ...interface{})

	Panic(...interface{})
	Panicf(string, ...interface{})
}

// NewJSONLogger uses logrus JSON formatter
func NewJSONLogger(topicProcessorName string, containerID int, debug bool) Logger {
	return newLogrus(topicProcessorName, containerID, debug, &logrus.JSONFormatter{})
}

// NewTextLogger uses logrus text formatter
func NewTextLogger(topicProcessorName string, containerID int, debug bool) Logger {
	return newLogrus(topicProcessorName, containerID, debug, &logrus.TextFormatter{})
}

func newLogrus(topicProcessorName string, containerID int, debug bool, formatter logrus.Formatter) Logger {
	logger := logrus.New()
	logger.Formatter = formatter
	if debug {
		logger.Level = logrus.DebugLevel
	} else {
		logger.Level = logrus.InfoLevel
	}
	return logger.
		WithField("type", "kasper").
		WithField("topic_processor_name", topicProcessorName).
		WithField("container_id", containerID)
}

type stdlibLogger struct {
	log   *stdlibLog.Logger
	debug bool
}

func (l *stdlibLogger) Debug(vs ...interface{}) {
	if l.debug {
		vs = append([]interface{}{"DEBUG "}, vs...)
		l.log.Print(vs...)
	}
}

func (l *stdlibLogger) Debugf(format string, vs ...interface{}) {
	if l.debug {
		l.log.Printf(fmt.Sprintf("DEBUG %s", format), vs...)
	}
}

func (l *stdlibLogger) Info(vs ...interface{}) {
	vs = append([]interface{}{"INFO "}, vs...)
	l.log.Print(vs...)
}

func (l *stdlibLogger) Infof(format string, vs ...interface{}) {
	l.log.Printf(fmt.Sprintf("INFO %s", format), vs...)
}

func (l *stdlibLogger) Panic(vs ...interface{}) {
	vs = append([]interface{}{"PANIC "}, vs...)
	l.log.Panic(vs...)
}

func (l *stdlibLogger) Panicf(format string, vs ...interface{}) {
	l.log.Panicf(fmt.Sprintf("PANIC %s", format), vs...)
}

// NewBasicLogger uses stdlib logger
func NewBasicLogger(debug bool) Logger {
	return &stdlibLogger{stdlibLog.New(os.Stderr, "(KASPER) ", stdlibLog.LstdFlags), debug}
}

type noopLogger struct{}

func (noopLogger) Debug(...interface{})          {}
func (noopLogger) Debugf(string, ...interface{}) {}
func (noopLogger) Info(...interface{})           {}
func (noopLogger) Infof(string, ...interface{})  {}
func (noopLogger) Panic(...interface{})          { panic("panic") }
func (noopLogger) Panicf(string, ...interface{}) { panic("panic") }

// SetLogger allows you to set custom logging interface for Kasper
func SetLogger(logger Logger) {
	log = logger
}
<|endoftext|>


<commit_before>// Copyright 2010 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package image

import (
	"strconv"
)

// A Point is an X, Y coordinate pair. The axes increase right and down.
type Point struct {
	X, Y int
}

// String returns a string representation of p like "(3,4)".
func (p Point) String() string {
	return "(" + strconv.Itoa(p.X) + "," + strconv.Itoa(p.Y) + ")"
}

// Add returns the vector p+q.
func (p Point) Add(q Point) Point {
	return Point{p.X + q.X, p.Y + q.Y}
}

// Sub returns the vector p-q.
func (p Point) Sub(q Point) Point {
	return Point{p.X - q.X, p.Y - q.Y}
}

// Mul returns the vector p*k.
func (p Point) Mul(k int) Point {
	return Point{p.X * k, p.Y * k}
}

// Div returns the vector p/k.
func (p Point) Div(k int) Point {
	return Point{p.X / k, p.Y / k}
}

// In returns whether p is in r.
func (p Point) In(r Rectangle) bool {
	return r.Min.X <= p.X && p.X < r.Max.X &&
		r.Min.Y <= p.Y && p.Y < r.Max.Y
}

// Mod returns the point q in r such that p.X-q.X is a multiple of r's width
// and p.Y-q.Y is a multiple of r's height.
func (p Point) Mod(r Rectangle) Point {
	w, h := r.Dx(), r.Dy()
	p = p.Sub(r.Min)
	p.X = p.X % w
	if p.X < 0 {
		p.X += w
	}
	p.Y = p.Y % h
	if p.Y < 0 {
		p.Y += h
	}
	return p.Add(r.Min)
}

// Eq returns whether p and q are equal.
func (p Point) Eq(q Point) bool {
	return p.X == q.X && p.Y == q.Y
}

// ZP is the zero Point.
var ZP Point

// Pt is shorthand for Point{X, Y}.
func Pt(X, Y int) Point {
	return Point{X, Y}
}

// A Rectangle contains the points with Min.X <= X < Max.X, Min.Y <= Y < Max.Y.
// It is well-formed if Min.X <= Max.X and likewise for Y. Points are always
// well-formed. A rectangle's methods always return well-formed outputs for
// well-formed inputs.
type Rectangle struct {
	Min, Max Point
}

// String returns a string representation of r like "(3,4)-(6,5)".
func (r Rectangle) String() string {
	return r.Min.String() + "-" + r.Max.String()
}

// Dx returns r's width.
func (r Rectangle) Dx() int {
	return r.Max.X - r.Min.X
}

// Dy returns r's height.
func (r Rectangle) Dy() int {
	return r.Max.Y - r.Min.Y
}

// Size returns r's width and height.
func (r Rectangle) Size() Point {
	return Point{
		r.Max.X - r.Min.X,
		r.Max.Y - r.Min.Y,
	}
}

// Add returns the rectangle r translated by p.
func (r Rectangle) Add(p Point) Rectangle {
	return Rectangle{
		Point{r.Min.X + p.X, r.Min.Y + p.Y},
		Point{r.Max.X + p.X, r.Max.Y + p.Y},
	}
}

// Add returns the rectangle r translated by -p.
func (r Rectangle) Sub(p Point) Rectangle {
	return Rectangle{
		Point{r.Min.X - p.X, r.Min.Y - p.Y},
		Point{r.Max.X - p.X, r.Max.Y - p.Y},
	}
}

// Inset returns the rectangle r inset by n, which may be negative. If either
// of r's dimensions is less than 2*n then an empty rectangle near the center
// of r will be returned.
func (r Rectangle) Inset(n int) Rectangle {
	if r.Dx() < 2*n {
		r.Min.X = (r.Min.X + r.Max.X) / 2
		r.Max.X = r.Min.X
	} else {
		r.Min.X += n
		r.Max.X -= n
	}
	if r.Dy() < 2*n {
		r.Min.Y = (r.Min.Y + r.Max.Y) / 2
		r.Max.Y = r.Min.Y
	} else {
		r.Min.Y += n
		r.Max.Y -= n
	}
	return r
}

// Intersect returns the largest rectangle contained by both r and s. If the
// two rectangles do not overlap then the zero rectangle will be returned.
func (r Rectangle) Intersect(s Rectangle) Rectangle {
	if r.Min.X < s.Min.X {
		r.Min.X = s.Min.X
	}
	if r.Min.Y < s.Min.Y {
		r.Min.Y = s.Min.Y
	}
	if r.Max.X > s.Max.X {
		r.Max.X = s.Max.X
	}
	if r.Max.Y > s.Max.Y {
		r.Max.Y = s.Max.Y
	}
	if r.Min.X > r.Max.X || r.Min.Y > r.Max.Y {
		return ZR
	}
	return r
}

// Union returns the smallest rectangle that contains both r and s.
func (r Rectangle) Union(s Rectangle) Rectangle {
	if r.Min.X > s.Min.X {
		r.Min.X = s.Min.X
	}
	if r.Min.Y > s.Min.Y {
		r.Min.Y = s.Min.Y
	}
	if r.Max.X < s.Max.X {
		r.Max.X = s.Max.X
	}
	if r.Max.Y < s.Max.Y {
		r.Max.Y = s.Max.Y
	}
	return r
}

// Empty returns whether the rectangle contains no points.
func (r Rectangle) Empty() bool {
	return r.Min.X >= r.Max.X || r.Min.Y >= r.Max.Y
}

// Eq returns whether r and s are equal.
func (r Rectangle) Eq(s Rectangle) bool {
	return r.Min.X == s.Min.X && r.Min.Y == s.Min.Y &&
		r.Max.X == s.Max.X && r.Max.Y == s.Max.Y
}

// Overlaps returns whether r and s have a non-empty intersection.
func (r Rectangle) Overlaps(s Rectangle) bool {
	return r.Min.X < s.Max.X && s.Min.X < r.Max.X &&
		r.Min.Y < s.Max.Y && s.Min.Y < r.Max.Y
}

// In returns whether every point in r is in s.
func (r Rectangle) In(s Rectangle) bool {
	if r.Empty() {
		return true
	}
	// Note that r.Max is an exclusive bound for r, so that r.In(s)
	// does not require that r.Max.In(s).
	return s.Min.X <= r.Min.X && r.Max.X <= s.Max.X &&
		s.Min.Y <= r.Min.Y && r.Max.Y <= s.Max.Y
}

// Canon returns the canonical version of r. The returned rectangle has minimum
// and maximum coordinates swapped if necessary so that it is well-formed.
func (r Rectangle) Canon() Rectangle {
	if r.Max.X < r.Min.X {
		r.Min.X, r.Max.X = r.Max.X, r.Min.X
	}
	if r.Max.Y < r.Min.Y {
		r.Min.Y, r.Max.Y = r.Max.Y, r.Min.Y
	}
	return r
}

// ZR is the zero Rectangle.
var ZR Rectangle

// Rect is shorthand for Rectangle{Pt(x0, y0), Pt(x1, y1)}.
func Rect(x0, y0, x1, y1 int) Rectangle {
	if x0 > x1 {
		x0, x1 = x1, x0
	}
	if y0 > y1 {
		y0, y1 = y1, y0
	}
	return Rectangle{Point{x0, y0}, Point{x1, y1}}
}
<commit_msg>image: fix typo in Rectangle.Sub comment.<commit_after>// Copyright 2010 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package image

import (
	"strconv"
)

// A Point is an X, Y coordinate pair. The axes increase right and down.
type Point struct {
	X, Y int
}

// String returns a string representation of p like "(3,4)".
func (p Point) String() string {
	return "(" + strconv.Itoa(p.X) + "," + strconv.Itoa(p.Y) + ")"
}

// Add returns the vector p+q.
func (p Point) Add(q Point) Point {
	return Point{p.X + q.X, p.Y + q.Y}
}

// Sub returns the vector p-q.
func (p Point) Sub(q Point) Point {
	return Point{p.X - q.X, p.Y - q.Y}
}

// Mul returns the vector p*k.
func (p Point) Mul(k int) Point {
	return Point{p.X * k, p.Y * k}
}

// Div returns the vector p/k.
func (p Point) Div(k int) Point {
	return Point{p.X / k, p.Y / k}
}

// In returns whether p is in r.
func (p Point) In(r Rectangle) bool {
	return r.Min.X <= p.X && p.X < r.Max.X &&
		r.Min.Y <= p.Y && p.Y < r.Max.Y
}

// Mod returns the point q in r such that p.X-q.X is a multiple of r's width
// and p.Y-q.Y is a multiple of r's height.
func (p Point) Mod(r Rectangle) Point {
	w, h := r.Dx(), r.Dy()
	p = p.Sub(r.Min)
	p.X = p.X % w
	if p.X < 0 {
		p.X += w
	}
	p.Y = p.Y % h
	if p.Y < 0 {
		p.Y += h
	}
	return p.Add(r.Min)
}

// Eq returns whether p and q are equal.
func (p Point) Eq(q Point) bool {
	return p.X == q.X && p.Y == q.Y
}

// ZP is the zero Point.
var ZP Point

// Pt is shorthand for Point{X, Y}.
func Pt(X, Y int) Point {
	return Point{X, Y}
}

// A Rectangle contains the points with Min.X <= X < Max.X, Min.Y <= Y < Max.Y.
// It is well-formed if Min.X <= Max.X and likewise for Y. Points are always
// well-formed. A rectangle's methods always return well-formed outputs for
// well-formed inputs.
type Rectangle struct {
	Min, Max Point
}

// String returns a string representation of r like "(3,4)-(6,5)".
func (r Rectangle) String() string {
	return r.Min.String() + "-" + r.Max.String()
}

// Dx returns r's width.
func (r Rectangle) Dx() int {
	return r.Max.X - r.Min.X
}

// Dy returns r's height.
func (r Rectangle) Dy() int {
	return r.Max.Y - r.Min.Y
}

// Size returns r's width and height.
func (r Rectangle) Size() Point {
	return Point{
		r.Max.X - r.Min.X,
		r.Max.Y - r.Min.Y,
	}
}

// Add returns the rectangle r translated by p.
func (r Rectangle) Add(p Point) Rectangle {
	return Rectangle{
		Point{r.Min.X + p.X, r.Min.Y + p.Y},
		Point{r.Max.X + p.X, r.Max.Y + p.Y},
	}
}

// Sub returns the rectangle r translated by -p.
func (r Rectangle) Sub(p Point) Rectangle {
	return Rectangle{
		Point{r.Min.X - p.X, r.Min.Y - p.Y},
		Point{r.Max.X - p.X, r.Max.Y - p.Y},
	}
}

// Inset returns the rectangle r inset by n, which may be negative. If either
// of r's dimensions is less than 2*n then an empty rectangle near the center
// of r will be returned.
func (r Rectangle) Inset(n int) Rectangle {
	if r.Dx() < 2*n {
		r.Min.X = (r.Min.X + r.Max.X) / 2
		r.Max.X = r.Min.X
	} else {
		r.Min.X += n
		r.Max.X -= n
	}
	if r.Dy() < 2*n {
		r.Min.Y = (r.Min.Y + r.Max.Y) / 2
		r.Max.Y = r.Min.Y
	} else {
		r.Min.Y += n
		r.Max.Y -= n
	}
	return r
}

// Intersect returns the largest rectangle contained by both r and s. If the
// two rectangles do not overlap then the zero rectangle will be returned.
func (r Rectangle) Intersect(s Rectangle) Rectangle {
	if r.Min.X < s.Min.X {
		r.Min.X = s.Min.X
	}
	if r.Min.Y < s.Min.Y {
		r.Min.Y = s.Min.Y
	}
	if r.Max.X > s.Max.X {
		r.Max.X = s.Max.X
	}
	if r.Max.Y > s.Max.Y {
		r.Max.Y = s.Max.Y
	}
	if r.Min.X > r.Max.X || r.Min.Y > r.Max.Y {
		return ZR
	}
	return r
}

// Union returns the smallest rectangle that contains both r and s.
func (r Rectangle) Union(s Rectangle) Rectangle {
	if r.Min.X > s.Min.X {
		r.Min.X = s.Min.X
	}
	if r.Min.Y > s.Min.Y {
		r.Min.Y = s.Min.Y
	}
	if r.Max.X < s.Max.X {
		r.Max.X = s.Max.X
	}
	if r.Max.Y < s.Max.Y {
		r.Max.Y = s.Max.Y
	}
	return r
}

// Empty returns whether the rectangle contains no points.
func (r Rectangle) Empty() bool {
	return r.Min.X >= r.Max.X || r.Min.Y >= r.Max.Y
}

// Eq returns whether r and s are equal.
func (r Rectangle) Eq(s Rectangle) bool {
	return r.Min.X == s.Min.X && r.Min.Y == s.Min.Y &&
		r.Max.X == s.Max.X && r.Max.Y == s.Max.Y
}

// Overlaps returns whether r and s have a non-empty intersection.
func (r Rectangle) Overlaps(s Rectangle) bool {
	return r.Min.X < s.Max.X && s.Min.X < r.Max.X &&
		r.Min.Y < s.Max.Y && s.Min.Y < r.Max.Y
}

// In returns whether every point in r is in s.
func (r Rectangle) In(s Rectangle) bool {
	if r.Empty() {
		return true
	}
	// Note that r.Max is an exclusive bound for r, so that r.In(s)
	// does not require that r.Max.In(s).
	return s.Min.X <= r.Min.X && r.Max.X <= s.Max.X &&
		s.Min.Y <= r.Min.Y && r.Max.Y <= s.Max.Y
}

// Canon returns the canonical version of r. The returned rectangle has minimum
// and maximum coordinates swapped if necessary so that it is well-formed.
func (r Rectangle) Canon() Rectangle {
	if r.Max.X < r.Min.X {
		r.Min.X, r.Max.X = r.Max.X, r.Min.X
	}
	if r.Max.Y < r.Min.Y {
		r.Min.Y, r.Max.Y = r.Max.Y, r.Min.Y
	}
	return r
}

// ZR is the zero Rectangle.
var ZR Rectangle

// Rect is shorthand for Rectangle{Pt(x0, y0), Pt(x1, y1)}.
func Rect(x0, y0, x1, y1 int) Rectangle {
	if x0 > x1 {
		x0, x1 = x1, x0
	}
	if y0 > y1 {
		y0, y1 = y1, y0
	}
	return Rectangle{Point{x0, y0}, Point{x1, y1}}
}
<|endoftext|>


<commit_before>// Copyright 2013, Örjan Persson. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Package logging implements a logging infrastructure for Go. It supports
// different logging backends like syslog, file and memory. Multiple backends
// can be utilized with different log levels per backend and logger.
package logging

import (
	"bytes"
	"fmt"
	"log"
	"os"
	"strings"
	"sync/atomic"
	"time"
)

// Redactor is an interface for types that may contain sensitive information
// (like passwords), which shouldn't be printed to the log. The idea was found
// in relog as part of the vitness project.
type Redactor interface {
	Redacted() interface{}
}

// Redact returns a string of * having the same length as s.
func Redact(s string) string {
	return strings.Repeat("*", len(s))
}

var (
	// Sequence number is incremented and utilized for all log records created.
	sequenceNo uint64

	// timeNow is a customizable for testing purposes.
	timeNow = time.Now
)

// Record represents a log record and contains the timestamp when the record
// was created, an increasing id, filename and line and finally the actual
// formatted log line.
type Record struct {
	Id     uint64
	Time   time.Time
	Module string
	Level  Level

	// message is kept as a pointer to have shallow copies update this once
	// needed.
	message   *string
	args      []interface{}
	fmt       string
	formatter Formatter
	formatted string
}

func (r *Record) Formatted(calldepth int) string {
	if r.formatted == "" {
		var buf bytes.Buffer
		r.formatter.Format(calldepth+1, r, &buf)
		r.formatted = buf.String()
	}
	return r.formatted
}

func (r *Record) Message() string {
	if r.message == nil {
		// Redact the arguments that implements the Redactor interface
		for i, arg := range r.args {
			if redactor, ok := arg.(Redactor); ok == true {
				r.args[i] = redactor.Redacted()
			}
		}
		msg := fmt.Sprintf(r.fmt, r.args...)
		r.message = &msg
	}
	return *r.message
}

type Logger struct {
	Module         string
	backend        LeveledBackend
	haveBackend    bool
	ExtraCalldepth int
}

func (l *Logger) SetBackend(backend LeveledBackend) {
	l.backend = backend
	l.haveBackend = true
}

// TODO call NewLogger and remove MustGetLogger?
// GetLogger creates and returns a Logger object based on the module name.
func GetLogger(module string) (*Logger, error) {
	return &Logger{Module: module}, nil
}

// MustGetLogger is like GetLogger but panics if the logger can't be created.
// It simplifies safe initialization of a global logger for eg. a package.
func MustGetLogger(module string) *Logger {
	logger, err := GetLogger(module)
	if err != nil {
		panic("logger: " + module + ": " + err.Error())
	}
	return logger
}

// Reset restores the internal state of the logging library.
func Reset() {
	// TODO make a global Init() method to be less magic? or make it such that
	// if there's no backends at all configured, we could use some tricks to
	// automatically setup backends based if we have a TTY or not.
	sequenceNo = 0
	b := SetBackend(NewLogBackend(os.Stderr, "", log.LstdFlags))
	b.SetLevel(DEBUG, "")
	SetFormatter(DefaultFormatter)
	timeNow = time.Now
}

// InitForTesting is a convenient method when using logging in a test. Once
// called, the time will be frozen to January 1, 1970 UTC.
func InitForTesting(level Level) *MemoryBackend {
	Reset()

	memoryBackend := NewMemoryBackend(10240)

	leveledBackend := AddModuleLevel(memoryBackend)
	leveledBackend.SetLevel(level, "")
	SetBackend(leveledBackend)

	timeNow = func() time.Time {
		return time.Unix(0, 0).UTC()
	}
	return memoryBackend
}

// IsEnabledFor returns true if the logger is enabled for the given level.
func (l *Logger) IsEnabledFor(level Level) bool {
	return defaultBackend.IsEnabledFor(level, l.Module)
}

func (l *Logger) log(lvl Level, format string, args ...interface{}) {
	// Create the logging record and pass it in to the backend
	record := &Record{
		Id:     atomic.AddUint64(&sequenceNo, 1),
		Time:   timeNow(),
		Module: l.Module,
		Level:  lvl,
		fmt:    format,
		args:   args,
	}

	// TODO use channels to fan out the records to all backends?
	// TODO in case of errors, do something (tricky)

	// calldepth=2 brings the stack up to the caller of the level
	// methods, Info(), Fatal(), etc.
	// ExtraCallDepth allows this to be extended further up the stack in case we
	// are wrapping these methods, eg. to expose them package level
	if l.haveBackend {
		l.backend.Log(lvl, 2+l.ExtraCalldepth, record)
		return
	}

	defaultBackend.Log(lvl, 2+l.ExtraCalldepth, record)
}

// Fatal is equivalent to l.Critical(fmt.Sprint()) followed by a call to os.Exit(1).
func (l *Logger) Fatal(args ...interface{}) {
	s := fmt.Sprint(args...)
	l.log(CRITICAL, "%s", s)
	os.Exit(1)
}

// Fatalf is equivalent to l.Critical followed by a call to os.Exit(1).
func (l *Logger) Fatalf(format string, args ...interface{}) {
	l.log(CRITICAL, format, args...)
	os.Exit(1)
}

// Panic is equivalent to l.Critical(fmt.Sprint()) followed by a call to panic().
func (l *Logger) Panic(args ...interface{}) {
	s := fmt.Sprint(args...)
	l.log(CRITICAL, "%s", s)
	panic(s)
}

// Panicf is equivalent to l.Critical followed by a call to panic().
func (l *Logger) Panicf(format string, args ...interface{}) {
	s := fmt.Sprintf(format, args...)
	l.log(CRITICAL, "%s", s)
	panic(s)
}

// Critical logs a message using CRITICAL as log level.
func (l *Logger) Critical(format string, args ...interface{}) {
	l.log(CRITICAL, format, args...)
}

// Error logs a message using ERROR as log level.
func (l *Logger) Error(format string, args ...interface{}) {
	l.log(ERROR, format, args...)
}

// Warning logs a message using WARNING as log level.
func (l *Logger) Warning(format string, args ...interface{}) {
	l.log(WARNING, format, args...)
}

// Notice logs a message using NOTICE as log level.
func (l *Logger) Notice(format string, args ...interface{}) {
	l.log(NOTICE, format, args...)
}

// Info logs a message using INFO as log level.
func (l *Logger) Info(format string, args ...interface{}) {
	l.log(INFO, format, args...)
}

// Debug logs a message using DEBUG as log level.
func (l *Logger) Debug(format string, args ...interface{}) {
	l.log(DEBUG, format, args...)
}

func init() {
	Reset()
}
<commit_msg>Add documentation to the Logger<commit_after>// Copyright 2013, Örjan Persson. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Package logging implements a logging infrastructure for Go. It supports
// different logging backends like syslog, file and memory. Multiple backends
// can be utilized with different log levels per backend and logger.
package logging

import (
	"bytes"
	"fmt"
	"log"
	"os"
	"strings"
	"sync/atomic"
	"time"
)

// Redactor is an interface for types that may contain sensitive information
// (like passwords), which shouldn't be printed to the log. The idea was found
// in relog as part of the vitness project.
type Redactor interface {
	Redacted() interface{}
}

// Redact returns a string of * having the same length as s.
func Redact(s string) string {
	return strings.Repeat("*", len(s))
}

var (
	// Sequence number is incremented and utilized for all log records created.
	sequenceNo uint64

	// timeNow is a customizable for testing purposes.
	timeNow = time.Now
)

// Record represents a log record and contains the timestamp when the record
// was created, an increasing id, filename and line and finally the actual
// formatted log line.
type Record struct {
	Id     uint64
	Time   time.Time
	Module string
	Level  Level

	// message is kept as a pointer to have shallow copies update this once
	// needed.
	message   *string
	args      []interface{}
	fmt       string
	formatter Formatter
	formatted string
}

func (r *Record) Formatted(calldepth int) string {
	if r.formatted == "" {
		var buf bytes.Buffer
		r.formatter.Format(calldepth+1, r, &buf)
		r.formatted = buf.String()
	}
	return r.formatted
}

func (r *Record) Message() string {
	if r.message == nil {
		// Redact the arguments that implements the Redactor interface
		for i, arg := range r.args {
			if redactor, ok := arg.(Redactor); ok == true {
				r.args[i] = redactor.Redacted()
			}
		}
		msg := fmt.Sprintf(r.fmt, r.args...)
		r.message = &msg
	}
	return *r.message
}

type Logger struct {
	Module      string
	backend     LeveledBackend
	haveBackend bool

	// ExtraCallDepth can be used to add additional call depth when getting the
	// calling function. This is normally used when wrapping a logger.
	ExtraCalldepth int
}

func (l *Logger) SetBackend(backend LeveledBackend) {
	l.backend = backend
	l.haveBackend = true
}

// TODO call NewLogger and remove MustGetLogger?
// GetLogger creates and returns a Logger object based on the module name.
func GetLogger(module string) (*Logger, error) {
	return &Logger{Module: module}, nil
}

// MustGetLogger is like GetLogger but panics if the logger can't be created.
// It simplifies safe initialization of a global logger for eg. a package.
func MustGetLogger(module string) *Logger {
	logger, err := GetLogger(module)
	if err != nil {
		panic("logger: " + module + ": " + err.Error())
	}
	return logger
}

// Reset restores the internal state of the logging library.
func Reset() {
	// TODO make a global Init() method to be less magic? or make it such that
	// if there's no backends at all configured, we could use some tricks to
	// automatically setup backends based if we have a TTY or not.
	sequenceNo = 0
	b := SetBackend(NewLogBackend(os.Stderr, "", log.LstdFlags))
	b.SetLevel(DEBUG, "")
	SetFormatter(DefaultFormatter)
	timeNow = time.Now
}

// InitForTesting is a convenient method when using logging in a test. Once
// called, the time will be frozen to January 1, 1970 UTC.
func InitForTesting(level Level) *MemoryBackend {
	Reset()

	memoryBackend := NewMemoryBackend(10240)

	leveledBackend := AddModuleLevel(memoryBackend)
	leveledBackend.SetLevel(level, "")
	SetBackend(leveledBackend)

	timeNow = func() time.Time {
		return time.Unix(0, 0).UTC()
	}
	return memoryBackend
}

// IsEnabledFor returns true if the logger is enabled for the given level.
func (l *Logger) IsEnabledFor(level Level) bool {
	return defaultBackend.IsEnabledFor(level, l.Module)
}

func (l *Logger) log(lvl Level, format string, args ...interface{}) {
	// Create the logging record and pass it in to the backend
	record := &Record{
		Id:     atomic.AddUint64(&sequenceNo, 1),
		Time:   timeNow(),
		Module: l.Module,
		Level:  lvl,
		fmt:    format,
		args:   args,
	}

	// TODO use channels to fan out the records to all backends?
	// TODO in case of errors, do something (tricky)

	// calldepth=2 brings the stack up to the caller of the level
	// methods, Info(), Fatal(), etc.
	// ExtraCallDepth allows this to be extended further up the stack in case we
	// are wrapping these methods, eg. to expose them package level
	if l.haveBackend {
		l.backend.Log(lvl, 2+l.ExtraCalldepth, record)
		return
	}

	defaultBackend.Log(lvl, 2+l.ExtraCalldepth, record)
}

// Fatal is equivalent to l.Critical(fmt.Sprint()) followed by a call to os.Exit(1).
func (l *Logger) Fatal(args ...interface{}) {
	s := fmt.Sprint(args...)
	l.log(CRITICAL, "%s", s)
	os.Exit(1)
}

// Fatalf is equivalent to l.Critical followed by a call to os.Exit(1).
func (l *Logger) Fatalf(format string, args ...interface{}) {
	l.log(CRITICAL, format, args...)
	os.Exit(1)
}

// Panic is equivalent to l.Critical(fmt.Sprint()) followed by a call to panic().
func (l *Logger) Panic(args ...interface{}) {
	s := fmt.Sprint(args...)
	l.log(CRITICAL, "%s", s)
	panic(s)
}

// Panicf is equivalent to l.Critical followed by a call to panic().
func (l *Logger) Panicf(format string, args ...interface{}) {
	s := fmt.Sprintf(format, args...)
	l.log(CRITICAL, "%s", s)
	panic(s)
}

// Critical logs a message using CRITICAL as log level.
func (l *Logger) Critical(format string, args ...interface{}) {
	l.log(CRITICAL, format, args...)
}

// Error logs a message using ERROR as log level.
func (l *Logger) Error(format string, args ...interface{}) {
	l.log(ERROR, format, args...)
}

// Warning logs a message using WARNING as log level.
func (l *Logger) Warning(format string, args ...interface{}) {
	l.log(WARNING, format, args...)
}

// Notice logs a message using NOTICE as log level.
func (l *Logger) Notice(format string, args ...interface{}) {
	l.log(NOTICE, format, args...)
}

// Info logs a message using INFO as log level.
func (l *Logger) Info(format string, args ...interface{}) {
	l.log(INFO, format, args...)
}

// Debug logs a message using DEBUG as log level.
func (l *Logger) Debug(format string, args ...interface{}) {
	l.log(DEBUG, format, args...)
}

func init() {
	Reset()
}
<|endoftext|>


<commit_before>package watchdog

import (
	"time"

	"github.com/efritz/backoff"
)

// Backoff is the interface to a backoff interval generator. See the
// backoff dependency for details.
type Backoff backoff.Backoff

// Retry is the interface to something which are invoked until success.
type Retry interface {
	// Some critical action, which should return true on success.
	Retry() bool
}

// Watcher invokes a Retry function until success.
type Watcher struct {
	retry    Retry
	backoff  Backoff
	watching bool

	// The channel on which a quit signal can be sent. The watcher will
	// shutdown its goroutines after receiving a value on this channel.
	quit chan struct{}

	// The channel on which a restart request signal is sent. Once a
	// value is received on this channel, the watcher will execute the
	// retry function until success (or a quit signal is received). If
	// the watcher is already attempting to retry, any values received
	// on this channel will be ignored.
	restart chan struct{}
}

// NewWatcher creates a new watcher with the given retry function and
// interval generator.
func NewWatcher(retry Retry, backoff Backoff) *Watcher {
	return &Watcher{
		retry:    retry,
		backoff:  backoff,
		watching: false,

		quit:    make(chan struct{}),
		restart: make(chan struct{}),
	}
}

// Start begins watching in a goroutine. The watcher will *immediately*
// attempt to invoke the retry function. The watcher will re-invoke the
// retry function on failure, with a delay in between tries. On success,
// the watcher waits for a retry signal, at which point the process
// repeats. The channel returned will receive a value after the retry
// function returns true. The user should read a value from this channel
// after a retry request signal is sent, as this channel is unbuffered.
func (w *Watcher) Start() <-chan struct{} {
	success := make(chan struct{})

	go func() {
		w.watching = true

		defer func() {
			w.watching = false
			close(success)
		}()

		for {
			// Immediately try to invoke the function. If this fails, then
			// we'll reset our backoff interval generator and start the
			// invocation loop.

			if !w.retry.Retry() {
				w.backoff.Reset()

				if !w.invocationLoop() {
					return
				}
			}

			success <- struct{}{}

			select {
			case <-w.restart:
			case <-w.quit:
				return
			}
		}
	}()

	return (<-chan struct{})(success)
}

// Repeatedly invoke the retry function in a loop until either the
// function returns true or a signal is read from the quit channel.
// We sleep some time (respecting the backoff intervals) in between
// invocations. We'll read values from the restart channel to keep
// it clear, but we will not do anything special. Return true when
// the function halts because an invocation of the retry function
// was successful.
func (w *Watcher) invocationLoop() bool {
	ch := make(chan struct{})
	defer close(ch)

	// Spawn a goroutine that will simply eat values off of the
	// restart channel so that we don't have to muck up the main
	// loop below. The follow goroutine will be cleaned up when
	// we close the channel ch created above.

	go func() {
		for {
			select {
			case <-ch:
				return
			case <-w.restart:
			}
		}
	}()

	for {
		interval := w.backoff.NextInterval()

		select {
		case <-time.After(interval):
			if w.retry.Retry() {
				return true
			}

		case <-w.quit:
			return false
		}
	}
}

// Stop kills the watcher routine so that no future calls to the
// retry function are attempted.
func (w *Watcher) Stop() {
	w.quit <- struct{}{}

}

// Check will request the watcher to re-invoke the retry function
// until success. If the watcher is already in a retry cycle, then
// this function has no observable effect. This method does not do
// anything if the Stop method has been called.
func (w *Watcher) Check() {
	if !w.watching {
		return
	}

	w.restart <- struct{}{}
}
<commit_msg>Add RetryFunc.<commit_after>package watchdog

import (
	"time"

	"github.com/efritz/backoff"
)

// Backoff is the interface to a backoff interval generator. See the
// backoff dependency for details.
type Backoff backoff.Backoff

// Retry is the interface to something which are invoked until success.
type Retry interface {
	// Some critical action, which should return true on success.
	Retry() bool
}

// RetryFunc is a function that can be applied as a Retry.
type RetryFunc func() bool

// Retry will execute the RetryFunc.
func (f RetryFunc) Retry() bool {
	return f()
}

// Watcher invokes a Retry function until success.
type Watcher struct {
	retry    Retry
	backoff  Backoff
	watching bool

	// The channel on which a quit signal can be sent. The watcher will
	// shutdown its goroutines after receiving a value on this channel.
	quit chan struct{}

	// The channel on which a restart request signal is sent. Once a
	// value is received on this channel, the watcher will execute the
	// retry function until success (or a quit signal is received). If
	// the watcher is already attempting to retry, any values received
	// on this channel will be ignored.
	restart chan struct{}
}

// NewWatcher creates a new watcher with the given retry function and
// interval generator.
func NewWatcher(retry Retry, backoff Backoff) *Watcher {
	return &Watcher{
		retry:    retry,
		backoff:  backoff,
		watching: false,

		quit:    make(chan struct{}),
		restart: make(chan struct{}),
	}
}

// Start begins watching in a goroutine. The watcher will *immediately*
// attempt to invoke the retry function. The watcher will re-invoke the
// retry function on failure, with a delay in between tries. On success,
// the watcher waits for a retry signal, at which point the process
// repeats. The channel returned will receive a value after the retry
// function returns true. The user should read a value from this channel
// after a retry request signal is sent, as this channel is unbuffered.
func (w *Watcher) Start() <-chan struct{} {
	success := make(chan struct{})

	go func() {
		w.watching = true

		defer func() {
			w.watching = false
			close(success)
		}()

		for {
			// Immediately try to invoke the function. If this fails, then
			// we'll reset our backoff interval generator and start the
			// invocation loop.

			if !w.retry.Retry() {
				w.backoff.Reset()

				if !w.invocationLoop() {
					return
				}
			}

			success <- struct{}{}

			select {
			case <-w.restart:
			case <-w.quit:
				return
			}
		}
	}()

	return (<-chan struct{})(success)
}

// Repeatedly invoke the retry function in a loop until either the
// function returns true or a signal is read from the quit channel.
// We sleep some time (respecting the backoff intervals) in between
// invocations. We'll read values from the restart channel to keep
// it clear, but we will not do anything special. Return true when
// the function halts because an invocation of the retry function
// was successful.
func (w *Watcher) invocationLoop() bool {
	ch := make(chan struct{})
	defer close(ch)

	// Spawn a goroutine that will simply eat values off of the
	// restart channel so that we don't have to muck up the main
	// loop below. The follow goroutine will be cleaned up when
	// we close the channel ch created above.

	go func() {
		for {
			select {
			case <-ch:
				return
			case <-w.restart:
			}
		}
	}()

	for {
		interval := w.backoff.NextInterval()

		select {
		case <-time.After(interval):
			if w.retry.Retry() {
				return true
			}

		case <-w.quit:
			return false
		}
	}
}

// Stop kills the watcher routine so that no future calls to the
// retry function are attempted.
func (w *Watcher) Stop() {
	w.quit <- struct{}{}

}

// Check will request the watcher to re-invoke the retry function
// until success. If the watcher is already in a retry cycle, then
// this function has no observable effect. This method does not do
// anything if the Stop method has been called.
func (w *Watcher) Check() {
	if !w.watching {
		return
	}

	w.restart <- struct{}{}
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"strings"
	"testing"

	"github.com/stretchr/testify/assert"
	git "github.com/thoughtworks/talisman/git_testing"
)

func TestNotHavingAnyOutgoingChangesShouldNotFail(t *testing.T) {
	withNewTmpGitRepo(func(gitPath string) {
		git.SetupBaselineFiles(gitPath, "simple-file")
		assert.Equal(t, 0, runTalisman(gitPath, "", ""), "Expected run() to return 0 if no input is available on stdin. This happens when there are no outgoing changes")
	})
}

func TestAddingSimpleFileShouldExitZero(t *testing.T) {
	withNewTmpGitRepo(func(gitPath string) {
		git.SetupBaselineFiles(gitPath, "simple-file")
		exitStatus := runTalisman(gitPath, git.EarliestCommit(gitPath), git.LatestCommit(gitPath))
		assert.Equal(t, 0, exitStatus, "Expected run() to return 0 and pass as no suspicious files are in the repo")
	})
}

func TestAddingSecretKeyShouldExitOne(t *testing.T) {
	withNewTmpGitRepo(func(gitPath string) {
		git.SetupBaselineFiles(gitPath, "simple-file")
		git.CreateFileWithContents(gitPath, "private.pem", "secret")
		git.AddAndcommit(gitPath, "*", "add private key")

		exitStatus := runTalisman(gitPath, git.EarliestCommit(gitPath), git.LatestCommit(gitPath))
		assert.Equal(t, 1, exitStatus, "Expected run() to return 1 and fail as pem file was present in the repo")
	})
}

func TestAddingSecretKeyShouldExitZeroIfPEMFilesAreIgnored(t *testing.T) {
	withNewTmpGitRepo(func(gitPath string) {
		git.SetupBaselineFiles(gitPath, "simple-file")
		git.CreateFileWithContents(gitPath, "private.pem", "secret")
		git.CreateFileWithContents(gitPath, ".talismanignore", "*.pem")
		git.AddAndcommit(gitPath, "*", "add private key")

		exitStatus := runTalisman(gitPath, git.EarliestCommit(gitPath), git.LatestCommit(gitPath))
		assert.Equal(t, 0, exitStatus, "Expected run() to return 0 and pass as pem file was ignored")
	})
}

func TestStagingSecretKeyShouldExitOneWhenPreCommitFlagIsSet(t *testing.T) {
	withNewTmpGitRepo(func(gitPath string) {
		git.SetupBaselineFiles(gitPath, "simple-file")
		git.CreateFileWithContents(gitPath, "private.pem", "secret")
		git.Add(gitPath, "*")

		options := Options{
			debug:   false,
			githook: "pre-commit",
		}

		exitStatus := runTalismanWithOptions(gitPath, options)
		assert.Equal(t, 1, exitStatus, "Expected run() to return 1 and fail as pem file was present in the repo")
	})
}

func runTalisman(gitPath, oldCommit, newCommit string) int {
	options := Options{
		debug:   false,
		githook: "pre-push",
	}
	return runTalismanWithOptions(gitPath, options)
}

func runTalismanWithOptions(gitPath string, options Options) int {
	os.Chdir(gitPath)
	return run(mockStdIn(git.EarliestCommit(gitPath), git.LatestCommit(gitPath)), options)
}

func withNewTmpGitRepo(gitOp func(gitPath string)) {
	WithNewTmpDirNamed("talisman-acceptance-test", func(gitPath string) {
		git.Init(gitPath)
		gitOp(gitPath)
	})
}

type DirOp func(dirName string)

func WithNewTmpDirNamed(dirName string, dop DirOp) {
	path, err := ioutil.TempDir(os.TempDir(), dirName)
	if err != nil {
		panic(err)
	}
	defer os.RemoveAll(path)
	dop(path)
}

func mockStdIn(oldSha string, newSha string) io.Reader {
	return strings.NewReader(fmt.Sprintf("master %s master %s\n", newSha, oldSha))
}
<commit_msg>remove unused parameters<commit_after>package main

import (
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"strings"
	"testing"

	"github.com/stretchr/testify/assert"
	git "github.com/thoughtworks/talisman/git_testing"
)

func TestNotHavingAnyOutgoingChangesShouldNotFail(t *testing.T) {
	withNewTmpGitRepo(func(gitPath string) {
		git.SetupBaselineFiles(gitPath, "simple-file")
		assert.Equal(t, 0, runTalisman(gitPath), "Expected run() to return 0 if no input is available on stdin. This happens when there are no outgoing changes")
	})
}

func TestAddingSimpleFileShouldExitZero(t *testing.T) {
	withNewTmpGitRepo(func(gitPath string) {
		git.SetupBaselineFiles(gitPath, "simple-file")
		exitStatus := runTalisman(gitPath)
		assert.Equal(t, 0, exitStatus, "Expected run() to return 0 and pass as no suspicious files are in the repo")
	})
}

func TestAddingSecretKeyShouldExitOne(t *testing.T) {
	withNewTmpGitRepo(func(gitPath string) {
		git.SetupBaselineFiles(gitPath, "simple-file")
		git.CreateFileWithContents(gitPath, "private.pem", "secret")
		git.AddAndcommit(gitPath, "*", "add private key")

		exitStatus := runTalisman(gitPath)
		assert.Equal(t, 1, exitStatus, "Expected run() to return 1 and fail as pem file was present in the repo")
	})
}

func TestAddingSecretKeyShouldExitZeroIfPEMFilesAreIgnored(t *testing.T) {
	withNewTmpGitRepo(func(gitPath string) {
		git.SetupBaselineFiles(gitPath, "simple-file")
		git.CreateFileWithContents(gitPath, "private.pem", "secret")
		git.CreateFileWithContents(gitPath, ".talismanignore", "*.pem")
		git.AddAndcommit(gitPath, "*", "add private key")

		exitStatus := runTalisman(gitPath)
		assert.Equal(t, 0, exitStatus, "Expected run() to return 0 and pass as pem file was ignored")
	})
}

func TestStagingSecretKeyShouldExitOneWhenPreCommitFlagIsSet(t *testing.T) {
	withNewTmpGitRepo(func(gitPath string) {
		git.SetupBaselineFiles(gitPath, "simple-file")
		git.CreateFileWithContents(gitPath, "private.pem", "secret")
		git.Add(gitPath, "*")

		options := Options{
			debug:   false,
			githook: "pre-commit",
		}

		exitStatus := runTalismanWithOptions(gitPath, options)
		assert.Equal(t, 1, exitStatus, "Expected run() to return 1 and fail as pem file was present in the repo")
	})
}

func runTalisman(gitPath string) int {
	options := Options{
		debug:   false,
		githook: "pre-push",
	}
	return runTalismanWithOptions(gitPath, options)
}

func runTalismanWithOptions(gitPath string, options Options) int {
	os.Chdir(gitPath)
	return run(mockStdIn(git.EarliestCommit(gitPath), git.LatestCommit(gitPath)), options)
}

func withNewTmpGitRepo(gitOp func(gitPath string)) {
	WithNewTmpDirNamed("talisman-acceptance-test", func(gitPath string) {
		git.Init(gitPath)
		gitOp(gitPath)
	})
}

type DirOp func(dirName string)

func WithNewTmpDirNamed(dirName string, dop DirOp) {
	path, err := ioutil.TempDir(os.TempDir(), dirName)
	if err != nil {
		panic(err)
	}
	defer os.RemoveAll(path)
	dop(path)
}

func mockStdIn(oldSha string, newSha string) io.Reader {
	return strings.NewReader(fmt.Sprintf("master %s master %s\n", newSha, oldSha))
}
<|endoftext|>


<commit_before>package console

import (
	"fmt"
	"github.com/name5566/leaf/conf"
	"os"
	"path"
	"runtime/pprof"
	"time"
)

var commands = []Command{
	new(CommandHelp),
	new(CommandCPUProf),
}

type Command interface {
	// must goroutine safe
	name() string
	// must goroutine safe
	help() string
	// must goroutine safe
	run(arg []string) string
}

// help
type CommandHelp struct{}

func (c *CommandHelp) name() string {
	return "help"
}

func (c *CommandHelp) help() string {
	return "This help text"
}

func (c *CommandHelp) run(arg []string) string {
	output := "Commands:\r\n"
	for i, c := range commands {
		output += c.name() + " - " + c.help()
		if i < len(commands)-1 {
			output += "\r\n"
		}
	}

	return output
}

// cpuprof
type CommandCPUProf struct{}

func (c *CommandCPUProf) name() string {
	return "cpuprof"
}

func (c *CommandCPUProf) help() string {
	return "CPU profiling for the current process"
}

func (c *CommandCPUProf) usage() string {
	return "Usage: cpuprof start|stop"
}

func (c *CommandCPUProf) run(arg []string) string {
	if len(arg) == 0 {
		return c.usage()
	}

	switch arg[0] {
	case "start":
		now := time.Now()
		fn := path.Join(conf.ProfilePath,
			fmt.Sprintf("%d%02d%02d_%02d_%02d_%02d.prof",
				now.Year(),
				now.Month(),
				now.Day(),
				now.Hour(),
				now.Minute(),
				now.Second()))
		f, err := os.Create(fn)
		if err != nil {
			return err.Error()
		}
		err = pprof.StartCPUProfile(f)
		if err != nil {
			f.Close()
			return err.Error()
		}
		return fn
	case "stop":
		pprof.StopCPUProfile()
		return ""
	default:
		return c.usage()
	}
}
<commit_msg>goroutine, heap, threadcreate, block profiling<commit_after>package console

import (
	"fmt"
	"github.com/name5566/leaf/conf"
	"os"
	"path"
	"runtime/pprof"
	"time"
)

var commands = []Command{
	new(CommandHelp),
	new(CommandCPUProf),
	new(CommandProf),
}

type Command interface {
	// must goroutine safe
	name() string
	// must goroutine safe
	help() string
	// must goroutine safe
	run(arg []string) string
}

// help
type CommandHelp struct{}

func (c *CommandHelp) name() string {
	return "help"
}

func (c *CommandHelp) help() string {
	return "This help text"
}

func (c *CommandHelp) run(arg []string) string {
	output := "Commands:\r\n"
	for i, c := range commands {
		output += c.name() + " - " + c.help()
		if i < len(commands)-1 {
			output += "\r\n"
		}
	}

	return output
}

// cpuprof
type CommandCPUProf struct{}

func (c *CommandCPUProf) name() string {
	return "cpuprof"
}

func (c *CommandCPUProf) help() string {
	return "CPU profiling for the current process"
}

func (c *CommandCPUProf) usage() string {
	return "cpuprof writes runtime profiling data in the format expected by \r\n" +
		"the pprof visualization tool\r\n\r\n" +
		"Usage: cpuprof start|stop\r\n" +
		"  start - enables CPU profiling\r\n" +
		"  stop  - stops the current CPU profile"
}

func (c *CommandCPUProf) run(arg []string) string {
	if len(arg) == 0 {
		return c.usage()
	}

	switch arg[0] {
	case "start":
		fn := profileName() + ".cpuprof"
		f, err := os.Create(fn)
		if err != nil {
			return err.Error()
		}
		err = pprof.StartCPUProfile(f)
		if err != nil {
			f.Close()
			return err.Error()
		}
		return fn
	case "stop":
		pprof.StopCPUProfile()
		return ""
	default:
		return c.usage()
	}
}

func profileName() string {
	now := time.Now()
	return path.Join(conf.ProfilePath,
		fmt.Sprintf("%d%02d%02d_%02d_%02d_%02d",
			now.Year(),
			now.Month(),
			now.Day(),
			now.Hour(),
			now.Minute(),
			now.Second()))
}

// prof
type CommandProf struct{}

func (c *CommandProf) name() string {
	return "prof"
}

func (c *CommandProf) help() string {
	return "Writes a pprof-formatted snapshot"
}

func (c *CommandProf) usage() string {
	return "prof writes runtime profiling data in the format expected by \r\n" +
		"the pprof visualization tool\r\n\r\n" +
		"Usage: prof goroutine|heap|thread|block\r\n" +
		"  goroutine - stack traces of all current goroutines\r\n" +
		"  heap      - a sampling of all heap allocations\r\n" +
		"  thread    - stack traces that led to the creation of new OS threads\r\n" +
		"  block     - stack traces that led to blocking on synchronization primitives"
}

func (c *CommandProf) run(arg []string) string {
	if len(arg) == 0 {
		return c.usage()
	}

	var (
		p  *pprof.Profile
		fn string
	)
	switch arg[0] {
	case "goroutine":
		p = pprof.Lookup("goroutine")
		fn = profileName() + ".gprof"
	case "heap":
		p = pprof.Lookup("heap")
		fn = profileName() + ".hprof"
	case "thread":
		p = pprof.Lookup("threadcreate")
		fn = profileName() + ".tprof"
	case "block":
		p = pprof.Lookup("block")
		fn = profileName() + ".bprof"
	default:
		return c.usage()
	}

	f, err := os.Create(fn)
	if err != nil {
		return err.Error()
	}
	defer f.Close()
	err = p.WriteTo(f, 0)
	if err != nil {
		return err.Error()
	}

	return fn
}
<|endoftext|>


<commit_before>package activity

import (
	"fmt"

	"time"

	"math"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/service/swf"
	"github.com/juju/errors"
	"github.com/sclasen/swfsm/fsm"
	. "github.com/sclasen/swfsm/log"
	"github.com/sclasen/swfsm/poller"
	. "github.com/sclasen/swfsm/sugar"
)

type ActivityTaskCanceledError struct {
	details string
}

func (e ActivityTaskCanceledError) Error() string {
	return "AcvitityTask canceled: " + e.details
}

func (e ActivityTaskCanceledError) Details() *string {
	if e.details == "" {
		return nil
	}
	dup := e.details
	return &dup
}

type SWFOps interface {
	RecordActivityTaskHeartbeat(req *swf.RecordActivityTaskHeartbeatInput) (*swf.RecordActivityTaskHeartbeatOutput, error)
	RespondActivityTaskCanceled(req *swf.RespondActivityTaskCanceledInput) (*swf.RespondActivityTaskCanceledOutput, error)
	RespondActivityTaskCompleted(req *swf.RespondActivityTaskCompletedInput) (*swf.RespondActivityTaskCompletedOutput, error)
	RespondActivityTaskFailed(req *swf.RespondActivityTaskFailedInput) (*swf.RespondActivityTaskFailedOutput, error)
	PollForActivityTask(req *swf.PollForActivityTaskInput) (*swf.PollForActivityTaskOutput, error)
	GetWorkflowExecutionHistory(req *swf.GetWorkflowExecutionHistoryInput) (*swf.GetWorkflowExecutionHistoryOutput, error)
	SignalWorkflowExecution(req *swf.SignalWorkflowExecutionInput) (*swf.SignalWorkflowExecutionOutput, error)
}

type ActivityWorker struct {
	Serializer       fsm.StateSerializer
	SystemSerializer fsm.StateSerializer
	// Domain of the workflow associated with the FSM.
	Domain string
	// TaskList that the underlying poller will poll for decision tasks.
	TaskList string
	// Identity used in PollForActivityTaskRequests, can be empty.
	Identity string
	// Client used to make SWF api requests.
	SWF SWFOps
	// Type Info for handled activities
	handlers map[string]*ActivityHandler
	// ShutdownManager
	ShutdownManager *poller.ShutdownManager
	// ActivityTaskDispatcher
	ActivityTaskDispatcher ActivityTaskDispatcher
	// ActivityInterceptor
	ActivityInterceptor ActivityInterceptor
	// allow panics in activities rather than recovering and failing the activity, useful for testing
	AllowPanics bool
	// reads the EventCorrelator and backs off based on what retry # the activity is.
	BackoffOnFailure bool
	// maximum backoff sleep on retries that fail.
	MaxBackoffSeconds int
}

func (a *ActivityWorker) AddHandler(handler *ActivityHandler) {
	if a.handlers == nil {
		a.handlers = map[string]*ActivityHandler{}
	}
	a.handlers[handler.Activity] = handler
}

func (a *ActivityWorker) Init() {
	if a.Serializer == nil {
		a.Serializer = fsm.JSONStateSerializer{}
	}

	if a.SystemSerializer == nil {
		a.SystemSerializer = fsm.JSONStateSerializer{}
	}

	if a.ActivityInterceptor == nil {
		a.ActivityInterceptor = &FuncInterceptor{}
	}

	if a.ActivityTaskDispatcher == nil {
		a.ActivityTaskDispatcher = &CallingGoroutineDispatcher{}
	}

	if a.ShutdownManager == nil {
		a.ShutdownManager = poller.NewShutdownManager()
	}
}

func (a *ActivityWorker) Start() {
	a.Init()
	poller := poller.NewActivityTaskPoller(a.SWF, a.Domain, a.Identity, a.TaskList)
	go poller.PollUntilShutdownBy(a.ShutdownManager, fmt.Sprintf("%s-poller", a.Identity), a.dispatchTask)
}

func (a *ActivityWorker) dispatchTask(activityTask *swf.PollForActivityTaskOutput) {
	if a.AllowPanics {
		a.ActivityTaskDispatcher.DispatchTask(activityTask, a.HandleActivityTask)
	} else {
		a.ActivityTaskDispatcher.DispatchTask(activityTask, a.handleWithRecovery(a.HandleActivityTask))
	}
}

// HandleActivityTask is the callback passed into the registered ActivityTaskDispatcher.
// It is exposed so that users can handle polling themselves and call DispatchTask directly
// with this as the callback.
//
// e.g.  activityWorker.ActivityTaskDispatcher.DispatchTask(activityTask, a.HandleActivityTask)
//
// Note: You will need to handle recovering from panics if you call this directly.
func (a *ActivityWorker) HandleActivityTask(activityTask *swf.PollForActivityTaskOutput) {
	a.ActivityInterceptor.BeforeTask(activityTask)
	handler := a.handlers[*activityTask.ActivityType.Name]

	if handler == nil {
		err := errors.NewErr("no handler for activity: %s", LS(activityTask.ActivityType.Name))
		a.ActivityInterceptor.AfterTaskFailed(activityTask, &err)
		a.fail(activityTask, &err)
		return
	}

	var deserialized interface{}
	if activityTask.Input != nil {
		switch handler.Input.(type) {
		case string:
			deserialized = *activityTask.Input
		default:
			deserialized = handler.ZeroInput()
			err := a.Serializer.Deserialize(*activityTask.Input, deserialized)
			if err != nil {
				a.ActivityInterceptor.AfterTaskFailed(activityTask, err)
				a.fail(activityTask, errors.Annotate(err, "deserialize"))
				return
			}
		}

	} else {
		deserialized = nil
	}

	result, err := handler.HandlerFunc(activityTask, deserialized)
	result, err = a.ActivityInterceptor.AfterTask(activityTask, result, err)
	if err != nil {
		if e, ok := err.(ActivityTaskCanceledError); ok {
			a.ActivityInterceptor.AfterTaskCanceled(activityTask, e.details)
			a.canceled(activityTask, e.Details())
		} else {
			a.ActivityInterceptor.AfterTaskFailed(activityTask, err)
			a.fail(activityTask, errors.Annotate(err, "handler"))
		}
	} else {
		a.ActivityInterceptor.AfterTaskComplete(activityTask, result)
		a.result(activityTask, result)
	}
}

func (a *ActivityWorker) result(activityTask *swf.PollForActivityTaskOutput, result interface{}) {
	switch t := result.(type) {
	case string:
		a.done(activityTask, &t)
	case nil:
		a.done(activityTask, nil)
	default:
		serialized, err := a.Serializer.Serialize(result)
		if err != nil {
			a.fail(activityTask, errors.Annotate(err, "serialize"))
		} else {
			a.done(activityTask, &serialized)
		}
	}
}

func (h *ActivityWorker) fail(task *swf.PollForActivityTaskOutput, err error) {
	if h.BackoffOnFailure {
		hist, err := h.SWF.GetWorkflowExecutionHistory(&swf.GetWorkflowExecutionHistoryInput{
			Domain:       S(h.Domain),
			Execution:    task.WorkflowExecution,
			ReverseOrder: aws.Bool(true),
		})
		if err == nil {
			for _, e := range hist.Events {
				if *e.EventType == swf.EventTypeMarkerRecorded && *e.MarkerRecordedEventAttributes.MarkerName == fsm.CorrelatorMarker {
					correlator := new(fsm.EventCorrelator)
					err := h.Serializer.Deserialize(*e.MarkerRecordedEventAttributes.Details, correlator)
					if err == nil {
						attempts := correlator.ActivityAttempts[*task.ActivityId]
						backoff := h.backoff(attempts)
						Log.Printf("workflow-id=%s activity-id=%s activity-id=%s at=retry-backoff attempts=%d sleep=%ds ", LS(task.WorkflowExecution.WorkflowId), LS(task.ActivityType.Name), LS(task.ActivityId), attempts, backoff)
						time.Sleep(time.Duration(backoff) * time.Second)
					}
					break
				}
			}
		}
	}
	Log.Printf("workflow-id=%s activity-id=%s activity-id=%s at=fail error=%q", LS(task.WorkflowExecution.WorkflowId), LS(task.ActivityType.Name), LS(task.ActivityId), err.Error())
	_, failErr := h.SWF.RespondActivityTaskFailed(&swf.RespondActivityTaskFailedInput{
		TaskToken: task.TaskToken,
		Reason:    S(err.Error()),
		Details:   S(err.Error()),
	})
	if failErr != nil {
		Log.Printf("workflow-id=%s activity-id=%s activity-id=%s at=failed-response-fail error=%q", LS(task.WorkflowExecution.WorkflowId), LS(task.ActivityType.Name), LS(task.ActivityId), failErr.Error())
	}
}

func (h *ActivityWorker) signalStart(activityTask *swf.PollForActivityTaskOutput, data interface{}) error {
	return h.signal(activityTask, fsm.ActivityStartedSignal, data)
}

func (h *ActivityWorker) signalUpdate(activityTask *swf.PollForActivityTaskOutput, data interface{}) error {
	return h.signal(activityTask, fsm.ActivityUpdatedSignal, data)
}

func (h *ActivityWorker) signal(activityTask *swf.PollForActivityTaskOutput, signal string, data interface{}) error {
	state := new(fsm.SerializedActivityState)
	state.ActivityId = *activityTask.ActivityId
	if data != nil {
		ser, err := h.Serializer.Serialize(data)
		if err != nil {
			return err
		}
		state.Input = &ser
	}

	serializedState, err := h.SystemSerializer.Serialize(state)
	if err != nil {
		return err
	}

	_, rerr := h.SWF.SignalWorkflowExecution(&swf.SignalWorkflowExecutionInput{
		Domain:     S(h.Domain),
		WorkflowId: activityTask.WorkflowExecution.WorkflowId,
		SignalName: S(signal),
		Input:      S(serializedState),
	})

	return rerr
}

func (h *ActivityWorker) backoff(attempts int) int {
	// 0.5, 1, 2, 4, 8...
	exp := attempts - 1
	if exp > 30 {
		//int wraps at 31
		exp = 30
	}
	backoff := int(math.Pow(2, float64(exp)))
	maxBackoff := h.MaxBackoffSeconds
	if backoff > maxBackoff {
		backoff = maxBackoff
	}
	return backoff
}

func (h *ActivityWorker) done(resp *swf.PollForActivityTaskOutput, result *string) {
	Log.Printf("workflow-id=%s activity-id=%s activity-id=%s at=done", LS(resp.WorkflowExecution.WorkflowId), LS(resp.ActivityType.Name), LS(resp.ActivityId))

	_, completeErr := h.SWF.RespondActivityTaskCompleted(&swf.RespondActivityTaskCompletedInput{
		TaskToken: resp.TaskToken,
		Result:    result,
	})
	if completeErr != nil {
		Log.Printf("workflow-id=%s activity-id=%s activity-id=%s at=completed-response-fail error=%q", LS(resp.WorkflowExecution.WorkflowId), LS(resp.ActivityType.Name), LS(resp.ActivityId), completeErr.Error())
	}
}

func (h *ActivityWorker) canceled(resp *swf.PollForActivityTaskOutput, details *string) {
	Log.Printf("workflow-id=%s activity-id=%s activity-id=%s at=canceled", LS(resp.WorkflowExecution.WorkflowId), LS(resp.ActivityType.Name), LS(resp.ActivityId))

	_, canceledErr := h.SWF.RespondActivityTaskCanceled(&swf.RespondActivityTaskCanceledInput{
		TaskToken: resp.TaskToken,
		Details:   details,
	})
	if canceledErr != nil {
		Log.Printf("workflow-id=%s activity-id=%s activity-id=%s at=canceled-response-fail error=%q", LS(resp.WorkflowExecution.WorkflowId), LS(resp.ActivityType.Name), LS(resp.ActivityId), canceledErr.Error())
	}
}

func (h *ActivityWorker) handleWithRecovery(handler func(*swf.PollForActivityTaskOutput)) func(*swf.PollForActivityTaskOutput) {
	return func(resp *swf.PollForActivityTaskOutput) {
		defer func() {
			var anErr error
			if r := recover(); r != nil {
				if err, ok := r.(error); ok && err != nil {
					anErr = err
				} else {
					anErr = errors.New("panic in activity with nil error")
				}
				Log.Printf("component=activity at=activity-panic-recovery-error error=%q", r)
				h.fail(resp, anErr)
			}
		}()
		handler(resp)

	}
}
<commit_msg>Expose HandleWithRecovery in worker<commit_after>package activity

import (
	"fmt"

	"time"

	"math"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/service/swf"
	"github.com/juju/errors"
	"github.com/sclasen/swfsm/fsm"
	. "github.com/sclasen/swfsm/log"
	"github.com/sclasen/swfsm/poller"
	. "github.com/sclasen/swfsm/sugar"
)

type ActivityTaskCanceledError struct {
	details string
}

func (e ActivityTaskCanceledError) Error() string {
	return "AcvitityTask canceled: " + e.details
}

func (e ActivityTaskCanceledError) Details() *string {
	if e.details == "" {
		return nil
	}
	dup := e.details
	return &dup
}

type SWFOps interface {
	RecordActivityTaskHeartbeat(req *swf.RecordActivityTaskHeartbeatInput) (*swf.RecordActivityTaskHeartbeatOutput, error)
	RespondActivityTaskCanceled(req *swf.RespondActivityTaskCanceledInput) (*swf.RespondActivityTaskCanceledOutput, error)
	RespondActivityTaskCompleted(req *swf.RespondActivityTaskCompletedInput) (*swf.RespondActivityTaskCompletedOutput, error)
	RespondActivityTaskFailed(req *swf.RespondActivityTaskFailedInput) (*swf.RespondActivityTaskFailedOutput, error)
	PollForActivityTask(req *swf.PollForActivityTaskInput) (*swf.PollForActivityTaskOutput, error)
	GetWorkflowExecutionHistory(req *swf.GetWorkflowExecutionHistoryInput) (*swf.GetWorkflowExecutionHistoryOutput, error)
	SignalWorkflowExecution(req *swf.SignalWorkflowExecutionInput) (*swf.SignalWorkflowExecutionOutput, error)
}

type ActivityWorker struct {
	Serializer       fsm.StateSerializer
	SystemSerializer fsm.StateSerializer
	// Domain of the workflow associated with the FSM.
	Domain string
	// TaskList that the underlying poller will poll for decision tasks.
	TaskList string
	// Identity used in PollForActivityTaskRequests, can be empty.
	Identity string
	// Client used to make SWF api requests.
	SWF SWFOps
	// Type Info for handled activities
	handlers map[string]*ActivityHandler
	// ShutdownManager
	ShutdownManager *poller.ShutdownManager
	// ActivityTaskDispatcher
	ActivityTaskDispatcher ActivityTaskDispatcher
	// ActivityInterceptor
	ActivityInterceptor ActivityInterceptor
	// allow panics in activities rather than recovering and failing the activity, useful for testing
	AllowPanics bool
	// reads the EventCorrelator and backs off based on what retry # the activity is.
	BackoffOnFailure bool
	// maximum backoff sleep on retries that fail.
	MaxBackoffSeconds int
}

func (a *ActivityWorker) AddHandler(handler *ActivityHandler) {
	if a.handlers == nil {
		a.handlers = map[string]*ActivityHandler{}
	}
	a.handlers[handler.Activity] = handler
}

func (a *ActivityWorker) Init() {
	if a.Serializer == nil {
		a.Serializer = fsm.JSONStateSerializer{}
	}

	if a.SystemSerializer == nil {
		a.SystemSerializer = fsm.JSONStateSerializer{}
	}

	if a.ActivityInterceptor == nil {
		a.ActivityInterceptor = &FuncInterceptor{}
	}

	if a.ActivityTaskDispatcher == nil {
		a.ActivityTaskDispatcher = &CallingGoroutineDispatcher{}
	}

	if a.ShutdownManager == nil {
		a.ShutdownManager = poller.NewShutdownManager()
	}
}

func (a *ActivityWorker) Start() {
	a.Init()
	poller := poller.NewActivityTaskPoller(a.SWF, a.Domain, a.Identity, a.TaskList)
	go poller.PollUntilShutdownBy(a.ShutdownManager, fmt.Sprintf("%s-poller", a.Identity), a.dispatchTask)
}

func (a *ActivityWorker) dispatchTask(activityTask *swf.PollForActivityTaskOutput) {
	if a.AllowPanics {
		a.ActivityTaskDispatcher.DispatchTask(activityTask, a.HandleActivityTask)
	} else {
		a.ActivityTaskDispatcher.DispatchTask(activityTask, a.HandleWithRecovery(a.HandleActivityTask))
	}
}

// HandleActivityTask is the callback passed into the registered ActivityTaskDispatcher.
// It is exposed so that users can handle polling themselves and call DispatchTask directly
// with this as the callback.
//
// e.g.  activityWorker.ActivityTaskDispatcher.DispatchTask(activityTask, a.HandleWithRecovery(a.HandleActivityTask))
//
// Note: You will need to handle recovering from panics if you call this directly without wrapping
// with HandleWithRecovery.
func (a *ActivityWorker) HandleActivityTask(activityTask *swf.PollForActivityTaskOutput) {
	a.ActivityInterceptor.BeforeTask(activityTask)
	handler := a.handlers[*activityTask.ActivityType.Name]

	if handler == nil {
		err := errors.NewErr("no handler for activity: %s", LS(activityTask.ActivityType.Name))
		a.ActivityInterceptor.AfterTaskFailed(activityTask, &err)
		a.fail(activityTask, &err)
		return
	}

	var deserialized interface{}
	if activityTask.Input != nil {
		switch handler.Input.(type) {
		case string:
			deserialized = *activityTask.Input
		default:
			deserialized = handler.ZeroInput()
			err := a.Serializer.Deserialize(*activityTask.Input, deserialized)
			if err != nil {
				a.ActivityInterceptor.AfterTaskFailed(activityTask, err)
				a.fail(activityTask, errors.Annotate(err, "deserialize"))
				return
			}
		}

	} else {
		deserialized = nil
	}

	result, err := handler.HandlerFunc(activityTask, deserialized)
	result, err = a.ActivityInterceptor.AfterTask(activityTask, result, err)
	if err != nil {
		if e, ok := err.(ActivityTaskCanceledError); ok {
			a.ActivityInterceptor.AfterTaskCanceled(activityTask, e.details)
			a.canceled(activityTask, e.Details())
		} else {
			a.ActivityInterceptor.AfterTaskFailed(activityTask, err)
			a.fail(activityTask, errors.Annotate(err, "handler"))
		}
	} else {
		a.ActivityInterceptor.AfterTaskComplete(activityTask, result)
		a.result(activityTask, result)
	}
}

func (a *ActivityWorker) result(activityTask *swf.PollForActivityTaskOutput, result interface{}) {
	switch t := result.(type) {
	case string:
		a.done(activityTask, &t)
	case nil:
		a.done(activityTask, nil)
	default:
		serialized, err := a.Serializer.Serialize(result)
		if err != nil {
			a.fail(activityTask, errors.Annotate(err, "serialize"))
		} else {
			a.done(activityTask, &serialized)
		}
	}
}

func (h *ActivityWorker) fail(task *swf.PollForActivityTaskOutput, err error) {
	if h.BackoffOnFailure {
		hist, err := h.SWF.GetWorkflowExecutionHistory(&swf.GetWorkflowExecutionHistoryInput{
			Domain:       S(h.Domain),
			Execution:    task.WorkflowExecution,
			ReverseOrder: aws.Bool(true),
		})
		if err == nil {
			for _, e := range hist.Events {
				if *e.EventType == swf.EventTypeMarkerRecorded && *e.MarkerRecordedEventAttributes.MarkerName == fsm.CorrelatorMarker {
					correlator := new(fsm.EventCorrelator)
					err := h.Serializer.Deserialize(*e.MarkerRecordedEventAttributes.Details, correlator)
					if err == nil {
						attempts := correlator.ActivityAttempts[*task.ActivityId]
						backoff := h.backoff(attempts)
						Log.Printf("workflow-id=%s activity-id=%s activity-id=%s at=retry-backoff attempts=%d sleep=%ds ", LS(task.WorkflowExecution.WorkflowId), LS(task.ActivityType.Name), LS(task.ActivityId), attempts, backoff)
						time.Sleep(time.Duration(backoff) * time.Second)
					}
					break
				}
			}
		}
	}
	Log.Printf("workflow-id=%s activity-id=%s activity-id=%s at=fail error=%q", LS(task.WorkflowExecution.WorkflowId), LS(task.ActivityType.Name), LS(task.ActivityId), err.Error())
	_, failErr := h.SWF.RespondActivityTaskFailed(&swf.RespondActivityTaskFailedInput{
		TaskToken: task.TaskToken,
		Reason:    S(err.Error()),
		Details:   S(err.Error()),
	})
	if failErr != nil {
		Log.Printf("workflow-id=%s activity-id=%s activity-id=%s at=failed-response-fail error=%q", LS(task.WorkflowExecution.WorkflowId), LS(task.ActivityType.Name), LS(task.ActivityId), failErr.Error())
	}
}

func (h *ActivityWorker) signalStart(activityTask *swf.PollForActivityTaskOutput, data interface{}) error {
	return h.signal(activityTask, fsm.ActivityStartedSignal, data)
}

func (h *ActivityWorker) signalUpdate(activityTask *swf.PollForActivityTaskOutput, data interface{}) error {
	return h.signal(activityTask, fsm.ActivityUpdatedSignal, data)
}

func (h *ActivityWorker) signal(activityTask *swf.PollForActivityTaskOutput, signal string, data interface{}) error {
	state := new(fsm.SerializedActivityState)
	state.ActivityId = *activityTask.ActivityId
	if data != nil {
		ser, err := h.Serializer.Serialize(data)
		if err != nil {
			return err
		}
		state.Input = &ser
	}

	serializedState, err := h.SystemSerializer.Serialize(state)
	if err != nil {
		return err
	}

	_, rerr := h.SWF.SignalWorkflowExecution(&swf.SignalWorkflowExecutionInput{
		Domain:     S(h.Domain),
		WorkflowId: activityTask.WorkflowExecution.WorkflowId,
		SignalName: S(signal),
		Input:      S(serializedState),
	})

	return rerr
}

func (h *ActivityWorker) backoff(attempts int) int {
	// 0.5, 1, 2, 4, 8...
	exp := attempts - 1
	if exp > 30 {
		//int wraps at 31
		exp = 30
	}
	backoff := int(math.Pow(2, float64(exp)))
	maxBackoff := h.MaxBackoffSeconds
	if backoff > maxBackoff {
		backoff = maxBackoff
	}
	return backoff
}

func (h *ActivityWorker) done(resp *swf.PollForActivityTaskOutput, result *string) {
	Log.Printf("workflow-id=%s activity-id=%s activity-id=%s at=done", LS(resp.WorkflowExecution.WorkflowId), LS(resp.ActivityType.Name), LS(resp.ActivityId))

	_, completeErr := h.SWF.RespondActivityTaskCompleted(&swf.RespondActivityTaskCompletedInput{
		TaskToken: resp.TaskToken,
		Result:    result,
	})
	if completeErr != nil {
		Log.Printf("workflow-id=%s activity-id=%s activity-id=%s at=completed-response-fail error=%q", LS(resp.WorkflowExecution.WorkflowId), LS(resp.ActivityType.Name), LS(resp.ActivityId), completeErr.Error())
	}
}

func (h *ActivityWorker) canceled(resp *swf.PollForActivityTaskOutput, details *string) {
	Log.Printf("workflow-id=%s activity-id=%s activity-id=%s at=canceled", LS(resp.WorkflowExecution.WorkflowId), LS(resp.ActivityType.Name), LS(resp.ActivityId))

	_, canceledErr := h.SWF.RespondActivityTaskCanceled(&swf.RespondActivityTaskCanceledInput{
		TaskToken: resp.TaskToken,
		Details:   details,
	})
	if canceledErr != nil {
		Log.Printf("workflow-id=%s activity-id=%s activity-id=%s at=canceled-response-fail error=%q", LS(resp.WorkflowExecution.WorkflowId), LS(resp.ActivityType.Name), LS(resp.ActivityId), canceledErr.Error())
	}
}

// HandleWithRecovery is used to wrap handler functions (such as HandleActivityTask)
// so they gracefully recover from panics.
func (h *ActivityWorker) HandleWithRecovery(handler func(*swf.PollForActivityTaskOutput)) func(*swf.PollForActivityTaskOutput) {
	return func(resp *swf.PollForActivityTaskOutput) {
		defer func() {
			var anErr error
			if r := recover(); r != nil {
				if err, ok := r.(error); ok && err != nil {
					anErr = err
				} else {
					anErr = errors.New("panic in activity with nil error")
				}
				Log.Printf("component=activity at=activity-panic-recovery-error error=%q", r)
				h.fail(resp, anErr)
			}
		}()
		handler(resp)

	}
}
<|endoftext|>


<commit_before>//This packages consists all handler funcs for the webserver
package web

import (
	"html/template"
	"log"
	"net/http"
	"os"
	db "gofire/database"
)

var templates *template.Template

func init() {
	tdir := os.Getenv("TEMPLATE")
	log.Printf("Template Directory: %s\n", tdir)

    templates = template.Must(template.ParseGlob(tdir))

}

const GofireSession = "gSession"

func CheckSession(r *http.Request)string{
	if cookie, err :=r.Cookie(GofireSession); err != nil{
		return ""
	}else{
		if db.IsSessionValid(cookie.Value){
			return cookie.Value
		}
		return ""
	}
	return ""
}

//Handler for the index-site
func IndexHandler(w http.ResponseWriter, r *http.Request) {
	//Session validation
	if token := CheckSession(r); token != ""{
		http.Redirect(w, r, "/chat", http.StatusFound)
		return
	}
	w.Header().Set("content-type", "text/html")
    templates.ExecuteTemplate(w, "login", nil)
}
<commit_msg>add StaticHandler<commit_after>//This packages consists all handler funcs for the webserver
package web

import (
	"html/template"
	"log"
	"net/http"
	"os"
	db "gofire/database"
    "fmt"
)

var templates *template.Template

var staticDir string

func init() {
	tdir := os.Getenv("TEMPLATE")
	log.Printf("Template Directory: %s\n", tdir)

    templates = template.Must(template.ParseGlob(tdir))

    staticDir = os.Getenv("STATIC")
    log.Println("Static Dir: ", staticDir)
}

const GofireSession = "gSession"

func CheckSession(r *http.Request)string{
	if cookie, err :=r.Cookie(GofireSession); err != nil{
		return ""
	}else{
		if db.IsSessionValid(cookie.Value){
			return cookie.Value
		}
		return ""
	}
	return ""
}

//Handler for the index-site
func IndexHandler(w http.ResponseWriter, r *http.Request) {
	//Session validation
	if token := CheckSession(r); token != ""{
		http.Redirect(w, r, "/chat", http.StatusFound)
		return
	}
	w.Header().Set("content-type", "text/html")
    templates.ExecuteTemplate(w, "login", nil)
}

func StaticHandler(w http.ResponseWriter, r *http.Request){
    http.ServeFile(w, r, fmt.Sprint(staticDir, r.URL.Path[1:]))
}
<|endoftext|>


<commit_before>package alConst

const (
	OpenApi = "https://openapi.alipay.com/gateway.do"
)

type Person struct {
	Name string
}

//const For request alipay
const (

	//customer
	ReqPay           = "alipay.trade.pay"
	ReqReverse       = "alipay.trade.cancel"
	ReqRefund        = "alipay.trade.refund"
	ReqQuery         = "alipay.trade.query"
	ReqScenceBarCode = "bar_code"

	ReqCharset  = "utf-8"
	ReqVersion  = "1.0"
	ReqSignType = "RSA"
	//common part
	RawAppId      = "app_id"
	RawMethod     = "method"
	RawTimeStamp  = "timestamp"
	RawCharset    = "charset"
	RawVersion    = "version"
	RawSignType   = "sign_type"
	RawOutTradeNo = "out_trade_no"

	RawBizContent = "biz_content"
	RawSign       = "sign"

	//direct pay
	RawAuthCode    = "auth_code"
	RawTotalAmount = "total_amount"
	RawSubject     = "subject"
	RawStoreId     = "store_id"

	RawSellerId     = "seller_id"
	RawTimeExpire   = "time_expire"
	RawExtendParams = "extend_params"
	RawScence       = "scene"

	//order query
	RawTradeNo = "trade_no"

	//refund
	RawRefundAmount = "refund_amount"
	RawOutRequestNo = "out_request_no"
	RawRefundReason = "refund_reason"
	//service provider
	RawSysServiceProviderId = "sys_service_provider_id"
)

//const For response alipay
const (
	RespPay     = "alipay_trade_pay_response"
	RespReverse = "alipay_trade_cancel_response"
	RespRefund  = "alipay_trade_refund_response"
	RespQuery   = "alipay_trade_query_response"

	//Sign      = "sign"
	RawCode      = "code"
	RawSubCode   = "sub_code"
	RawMsg       = "msg"
	RawSubMsg    = "sub_msg"
	RawRetryFlag = "retry_flag"

	//direct pay
	//TotalAmount = "total_amount"

	//order Query
	RawTradeStatus = "trade_status"

	//refund
	RawRefundFee   = "refund_fee"
	RawOutRefundNo = "out_refund_no"
	//OutTradeNo  = "out_trade_no"
	//TradeNo     = "trade_no"

	//Reverse

)

const (
	AppId            = "AppId"
	SellerPrivateKey = "SellerPrivateKey"
	AliPublicKey     = "AliPublicKey"
	OutTradeNo       = "OutTradeNo"
	ALAuthToken      = "ALAuthToken"

	AuthCode    = "AuthCode"
	TotalAmount = "TotalAmount"
	Subject     = "Subject"
	StoreId     = "StoreId"

	SellerId     = "SellerId"
	TimeExpire   = "TimeExpire"
	ExtendParams = "ExtendParams"
	//query
	TradeNo = "TradeNo"

	//refund
	OutRequestNo = "OutRequestNo"
	RefundReason = "RefundReason"
	RefundAmount = "RefundAmount"
)
<commit_msg>SysServiceProviderId<commit_after>package alConst

const (
	OpenApi = "https://openapi.alipay.com/gateway.do"
)

type Person struct {
	Name string
}

//const For request alipay
const (

	//customer
	ReqPay           = "alipay.trade.pay"
	ReqReverse       = "alipay.trade.cancel"
	ReqRefund        = "alipay.trade.refund"
	ReqQuery         = "alipay.trade.query"
	ReqScenceBarCode = "bar_code"

	ReqCharset  = "utf-8"
	ReqVersion  = "1.0"
	ReqSignType = "RSA"
	//common part
	RawAppId      = "app_id"
	RawMethod     = "method"
	RawTimeStamp  = "timestamp"
	RawCharset    = "charset"
	RawVersion    = "version"
	RawSignType   = "sign_type"
	RawOutTradeNo = "out_trade_no"

	RawBizContent = "biz_content"
	RawSign       = "sign"

	//direct pay
	RawAuthCode    = "auth_code"
	RawTotalAmount = "total_amount"
	RawSubject     = "subject"
	RawStoreId     = "store_id"

	RawSellerId     = "seller_id"
	RawTimeExpire   = "time_expire"
	RawExtendParams = "extend_params"
	RawScence       = "scene"

	//order query
	RawTradeNo = "trade_no"

	//refund
	RawRefundAmount = "refund_amount"
	RawOutRequestNo = "out_request_no"
	RawRefundReason = "refund_reason"
	//service provider
	RawSysServiceProviderId = "sys_service_provider_id"
)

//const For response alipay
const (
	RespPay     = "alipay_trade_pay_response"
	RespReverse = "alipay_trade_cancel_response"
	RespRefund  = "alipay_trade_refund_response"
	RespQuery   = "alipay_trade_query_response"

	//Sign      = "sign"
	RawCode      = "code"
	RawSubCode   = "sub_code"
	RawMsg       = "msg"
	RawSubMsg    = "sub_msg"
	RawRetryFlag = "retry_flag"

	//direct pay
	//TotalAmount = "total_amount"

	//order Query
	RawTradeStatus = "trade_status"

	//refund
	RawRefundFee   = "refund_fee"
	RawOutRefundNo = "out_refund_no"
	//OutTradeNo  = "out_trade_no"
	//TradeNo     = "trade_no"

	//Reverse

)

const (
	AppId            = "AppId"
	SellerPrivateKey = "SellerPrivateKey"
	AliPublicKey     = "AliPublicKey"
	OutTradeNo       = "OutTradeNo"
	ALAuthToken      = "ALAuthToken"

	AuthCode    = "AuthCode"
	TotalAmount = "TotalAmount"
	Subject     = "Subject"
	StoreId     = "StoreId"

	SellerId     = "SellerId"
	TimeExpire   = "TimeExpire"
	ExtendParams = "ExtendParams"
	//query
	TradeNo = "TradeNo"

	//refund
	OutRequestNo         = "OutRequestNo"
	RefundReason         = "RefundReason"
	RefundAmount         = "RefundAmount"
	SysServiceProviderId = "SysServiceProviderId"
)
<|endoftext|>


<commit_before>// Copyright (C) 2015 Thomas de Zeeuw.
//
// Licensed onder the MIT license that can be found in the LICENSE file.

// Package logger provides multiple ways to log information of different levels
// of importance. No default logger is created, but Get is provided to get any
// logger at any location. See the provided examples, both in the documentation
// and the _examples directory (for complete examples).
package logger

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

const (
	defaultStackSize = 8192
	defaultLogsSize  = 1024
)

// MsgWriter takes a msg and writes it to the output.
type MsgWriter interface {
	Write(Msg) error
	Close() error
}

// Collection of all created loggers by name, used by the Get function.
var loggers = map[string]*Logger{}

// The Logger is an logging object which logs to a MsgWriter. Each logging
// operation makes a single call to the Writer's Write method, but not
// necessarily at the same time a Log operation is called. A Logger can be
// used simultaneously from multiple goroutines, it guarantees to serialize
// access to the MsgWriter.
//
// There are six different log levels (from higher to lower): Fatal, Error,
// Warn, Info, Thumb, Debug and Trace.
//
// Note: Log operations (Fatal, Error etc.) don't instally write to the
// MsgWriter, before closing the application call Logger.Close to ensure that
// all log operations are written to the MsgWriter.
type Logger struct {
	Name string

	// All errors, which can be read after Logger.Close is called, NOT THREAT
	// SAFE.
	Errors []error

	mw          MsgWriter
	minLogLevel LogLevel
	logs        chan Msg
	closed      chan struct{}
}

// Fatal logs a recovered error which could have killed the application. Fatal
// adds a stack trace as Msg.Data to the Msg.
func (l *Logger) Fatal(tags Tags, recv interface{}) {
	// Capture the stack trace.
	stackTrace := make([]byte, defaultStackSize)
	n := runtime.Stack(stackTrace, false)
	stackTrace = stackTrace[:n]

	msg := interfaceToString(recv)
	l.logs <- Msg{Fatal, msg, tags, time.Now(), stackTrace}
}

// Error logs a recoverable error.
func (l *Logger) Error(tags Tags, err error) {
	l.logs <- Msg{Error, err.Error(), tags, time.Now(), nil}
}

// Warn logs a warning message.
func (l *Logger) Warn(tags Tags, format string, v ...interface{}) {
	l.logs <- Msg{Warn, fmt.Sprintf(format, v...), tags, time.Now(), nil}
}

// Info logs an informational message.
func (l *Logger) Info(tags Tags, format string, v ...interface{}) {
	l.logs <- Msg{Info, fmt.Sprintf(format, v...), tags, time.Now(), nil}
}

// Debug logs the lowest level of information, only usefull when debugging
// the application. Only shows when Logger.ShowDebug is set to true, which
// defaults to false.
func (l *Logger) Debug(tags Tags, format string, v ...interface{}) {
	l.logs <- Msg{Debug, fmt.Sprintf(format, v...), tags, time.Now(), nil}
}

// Thumbstone indicates a function is still used in production. When developing
// software it's possible to introduce dead code with updates and new features.
// If a function is being suspected of being dead (not used) in production, add
// a call to Thumbstone and check the production logs to see if you're right.
//
// The caller of the (possibly) dead function will be put in the message, using
// the following format:
//	Function functionName called by callerFunctionName, from file /path/to/file on line lineNumber
// For example:
//	Function myFunction called by main.main, from file /main.go on line 20
func (l *Logger) Thumbstone(tags Tags, functionName string) {
	var msg string

	// Get caller information.
	pc, file, line, ok := runtime.Caller(2)
	if ok {
		fn := runtime.FuncForPC(pc)
		msg = fmt.Sprintf("Function %s called by %s, from file %s on line %d",
			functionName, fn.Name(), file, line)
	} else {
		msg = "Function " + functionName + " called from unkown location"
	}

	l.logs <- Msg{Thumb, msg, tags, time.Now(), nil}
}

// Message logs the given message.
//
// Note: the timestamp is always set to  the time of calling the function.
func (l *Logger) Message(msg Msg) {
	msg.Timestamp = time.Now()
	l.logs <- msg
}

// Set the minimum log level to log. See the order of the log level at the
// LogLevel constants documentation.
//
// Note: NOT THREAT SAFE.
func (l *Logger) SetMinLogLevel(min LogLevel) {
	l.minLogLevel = min
}

// Close blocks until all logs are written to the writer. After all logs are
// written it will call Close() on the message writer.
//
// Note: if a log operation is called after Close is called it will panic.
func (l *Logger) Close() error {
	close(l.logs)
	<-l.closed
	if l.mw != nil {
		return l.mw.Close()
	}
	return nil
}

// New creates a new logger, which starts a go routine which writes to the
// message writer, this way the main thread won't be blocked. Name is the name
// of the logger, used in getting the logger, via Get, from any location within
// your code. The logger is thread same and won't block, unless the message
// channel buffer is full.
//
// Because the logging isn't done on the main thread it's possible that the
// program will close before all the log items are written to the writer. It is
// required to call Logger.Close() before closing down the program! Otherwise
// logs might be lost!
//
// After calling Logger.Close(), log.Errors can be accessed to check for any
// writing errors from the log operations. Any call to Logger.Error,Info etc
// will panic!
func New(name string, mw MsgWriter) (*Logger, error) {
	log, err := new(name, mw)
	if err != nil {
		return nil, err
	}

	go logWriter(log)
	return log, nil
}

// Get gets a logger by its name.
func Get(name string) (*Logger, error) {
	log, ok := loggers[name]
	if !ok {
		return nil, errors.New("logger: no logger found with name " + name)
	}
	return log, nil
}

func new(name string, mw MsgWriter) (*Logger, error) {
	if _, ok := loggers[name]; ok {
		return nil, errors.New("logger: name " + name + " already taken")
	}

	log := &Logger{
		Name:   name,
		mw:     mw,
		logs:   make(chan Msg, defaultLogsSize),
		closed: make(chan struct{}, 1), // Can't block.
	}
	loggers[name] = log

	return log, nil
}

// Needs to be run in it's own goroutine, it blocks until log.logs is closed.
func logWriter(log *Logger) {
	for msg := range log.logs {
		if msg.Level < log.minLogLevel {
			continue
		}

		if err := log.mw.Write(msg); err != nil {
			log.Errors = append(log.Errors, err)
		}
	}

	log.closed <- struct{}{}
}

func interfaceToString(value interface{}) string {
	switch v := value.(type) {
	case string:
		return v
	case fmt.Stringer:
		return v.String()
	case []byte:
		return string(v)
	case error:
		return v.Error()
	}
	return fmt.Sprintf("%v", value)
}
<commit_msg>Update package doc<commit_after>// Copyright (C) 2015 Thomas de Zeeuw.
//
// Licensed onder the MIT license that can be found in the LICENSE file.

// Package logger is a asynchronous logging package, hence the name logger. It
// is build for customisation and speed. It uses a custom log writer so any
// custom backend can be used to store the logs. Logger provides multiple ways
// to log information of different levels of importance. No default logger is
// created, but Get is provided to get any logger from any location. See the
// provided examples, both in the documentation and the _examples directory
// (for complete examples).
package logger

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

const (
	defaultStackSize = 8192
	defaultLogsSize  = 1024
)

// MsgWriter takes a msg and writes it to the output.
type MsgWriter interface {
	Write(Msg) error
	Close() error
}

// Collection of all created loggers by name, used by the Get function.
var loggers = map[string]*Logger{}

// The Logger is an logging object which logs to a MsgWriter. Each logging
// operation makes a single call to the Writer's Write method, but not
// necessarily at the same time a Log operation is called. A Logger can be
// used simultaneously from multiple goroutines, it guarantees to serialize
// access to the MsgWriter.
//
// There are six different log levels (from higher to lower): Fatal, Error,
// Warn, Info, Thumb, Debug and Trace.
//
// Note: Log operations (Fatal, Error etc.) don't instally write to the
// MsgWriter, before closing the application call Logger.Close to ensure that
// all log operations are written to the MsgWriter.
type Logger struct {
	Name string

	// All errors, which can be read after Logger.Close is called, NOT THREAT
	// SAFE.
	Errors []error

	mw          MsgWriter
	minLogLevel LogLevel
	logs        chan Msg
	closed      chan struct{}
}

// Fatal logs a recovered error which could have killed the application. Fatal
// adds a stack trace as Msg.Data to the Msg.
func (l *Logger) Fatal(tags Tags, recv interface{}) {
	// Capture the stack trace.
	stackTrace := make([]byte, defaultStackSize)
	n := runtime.Stack(stackTrace, false)
	stackTrace = stackTrace[:n]

	msg := interfaceToString(recv)
	l.logs <- Msg{Fatal, msg, tags, time.Now(), stackTrace}
}

// Error logs a recoverable error.
func (l *Logger) Error(tags Tags, err error) {
	l.logs <- Msg{Error, err.Error(), tags, time.Now(), nil}
}

// Warn logs a warning message.
func (l *Logger) Warn(tags Tags, format string, v ...interface{}) {
	l.logs <- Msg{Warn, fmt.Sprintf(format, v...), tags, time.Now(), nil}
}

// Info logs an informational message.
func (l *Logger) Info(tags Tags, format string, v ...interface{}) {
	l.logs <- Msg{Info, fmt.Sprintf(format, v...), tags, time.Now(), nil}
}

// Debug logs the lowest level of information, only usefull when debugging
// the application. Only shows when Logger.ShowDebug is set to true, which
// defaults to false.
func (l *Logger) Debug(tags Tags, format string, v ...interface{}) {
	l.logs <- Msg{Debug, fmt.Sprintf(format, v...), tags, time.Now(), nil}
}

// Thumbstone indicates a function is still used in production. When developing
// software it's possible to introduce dead code with updates and new features.
// If a function is being suspected of being dead (not used) in production, add
// a call to Thumbstone and check the production logs to see if you're right.
//
// The caller of the (possibly) dead function will be put in the message, using
// the following format:
//	Function functionName called by callerFunctionName, from file /path/to/file on line lineNumber
// For example:
//	Function myFunction called by main.main, from file /main.go on line 20
func (l *Logger) Thumbstone(tags Tags, functionName string) {
	var msg string

	// Get caller information.
	pc, file, line, ok := runtime.Caller(2)
	if ok {
		fn := runtime.FuncForPC(pc)
		msg = fmt.Sprintf("Function %s called by %s, from file %s on line %d",
			functionName, fn.Name(), file, line)
	} else {
		msg = "Function " + functionName + " called from unkown location"
	}

	l.logs <- Msg{Thumb, msg, tags, time.Now(), nil}
}

// Message logs the given message.
//
// Note: the timestamp is always set to  the time of calling the function.
func (l *Logger) Message(msg Msg) {
	msg.Timestamp = time.Now()
	l.logs <- msg
}

// Set the minimum log level to log. See the order of the log level at the
// LogLevel constants documentation.
//
// Note: NOT THREAT SAFE.
func (l *Logger) SetMinLogLevel(min LogLevel) {
	l.minLogLevel = min
}

// Close blocks until all logs are written to the writer. After all logs are
// written it will call Close() on the message writer.
//
// Note: if a log operation is called after Close is called it will panic.
func (l *Logger) Close() error {
	close(l.logs)
	<-l.closed
	if l.mw != nil {
		return l.mw.Close()
	}
	return nil
}

// New creates a new logger, which starts a go routine which writes to the
// message writer, this way the main thread won't be blocked. Name is the name
// of the logger, used in getting the logger, via Get, from any location within
// your code. The logger is thread same and won't block, unless the message
// channel buffer is full.
//
// Because the logging isn't done on the main thread it's possible that the
// program will close before all the log items are written to the writer. It is
// required to call Logger.Close() before closing down the program! Otherwise
// logs might be lost!
//
// After calling Logger.Close(), log.Errors can be accessed to check for any
// writing errors from the log operations. Any call to Logger.Error,Info etc
// will panic!
func New(name string, mw MsgWriter) (*Logger, error) {
	log, err := new(name, mw)
	if err != nil {
		return nil, err
	}

	go logWriter(log)
	return log, nil
}

// Get gets a logger by its name.
func Get(name string) (*Logger, error) {
	log, ok := loggers[name]
	if !ok {
		return nil, errors.New("logger: no logger found with name " + name)
	}
	return log, nil
}

func new(name string, mw MsgWriter) (*Logger, error) {
	if _, ok := loggers[name]; ok {
		return nil, errors.New("logger: name " + name + " already taken")
	}

	log := &Logger{
		Name:   name,
		mw:     mw,
		logs:   make(chan Msg, defaultLogsSize),
		closed: make(chan struct{}, 1), // Can't block.
	}
	loggers[name] = log

	return log, nil
}

// Needs to be run in it's own goroutine, it blocks until log.logs is closed.
func logWriter(log *Logger) {
	for msg := range log.logs {
		if msg.Level < log.minLogLevel {
			continue
		}

		if err := log.mw.Write(msg); err != nil {
			log.Errors = append(log.Errors, err)
		}
	}

	log.closed <- struct{}{}
}

func interfaceToString(value interface{}) string {
	switch v := value.(type) {
	case string:
		return v
	case fmt.Stringer:
		return v.String()
	case []byte:
		return string(v)
	case error:
		return v.Error()
	}
	return fmt.Sprintf("%v", value)
}
<|endoftext|>