<commit_before>// Copyright (c) 2013-2016 The btcsuite developers
// Copyright (c) 2015-2019 The Decred developers
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.

package main

import (
	"fmt"
	"net/http"
	_ "net/http/pprof"
	"os"
	"runtime"
	"runtime/debug"
	"runtime/pprof"

	"github.com/decred/dcrd/blockchain/v3/indexers"
	"github.com/decred/dcrd/internal/limits"
	"github.com/decred/dcrd/internal/version"
)

var cfg *config

// winServiceMain is only invoked on Windows.  It detects when dcrd is running
// as a service and reacts accordingly.
var winServiceMain func() (bool, error)

// serviceStartOfDayChan is only used by Windows when the code is running as a
// service.  It signals the service code that startup has completed.  Notice
// that it uses a buffered channel so the caller will not be blocked when the
// service is not running.
var serviceStartOfDayChan = make(chan *config, 1)

// dcrdMain is the real main function for dcrd.  It is necessary to work around
// the fact that deferred functions do not run when os.Exit() is called.
func dcrdMain() error {
	// Load configuration and parse command line.  This function also
	// initializes logging and configures it accordingly.
	tcfg, _, err := loadConfig()
	if err != nil {
		return err
	}
	cfg = tcfg
	defer func() {
		if logRotator != nil {
			logRotator.Close()
		}
	}()

	// Get a context that will be canceled when a shutdown signal has been
	// triggered either from an OS signal such as SIGINT (Ctrl+C) or from
	// another subsystem such as the RPC server.
	ctx := shutdownListener()
	defer dcrdLog.Info("Shutdown complete")

	// Show version and home dir at startup.
	dcrdLog.Infof("Version %s (Go version %s %s/%s)", version.String(),
		runtime.Version(), runtime.GOOS, runtime.GOARCH)
	dcrdLog.Infof("Home dir: %s", cfg.HomeDir)
	if cfg.NoFileLogging {
		dcrdLog.Info("File logging disabled")
	}

	// Enable http profiling server if requested.
	if cfg.Profile != "" {
		go func() {
			listenAddr := cfg.Profile
			dcrdLog.Infof("Creating profiling server "+
				"listening on %s", listenAddr)
			profileRedirect := http.RedirectHandler("/debug/pprof",
				http.StatusSeeOther)
			http.Handle("/", profileRedirect)
			err := http.ListenAndServe(listenAddr, nil)
			if err != nil {
				fatalf(err.Error())
			}
		}()
	}

	// Write cpu profile if requested.
	if cfg.CPUProfile != "" {
		f, err := os.Create(cfg.CPUProfile)
		if err != nil {
			dcrdLog.Errorf("Unable to create cpu profile: %v", err.Error())
			return err
		}
		pprof.StartCPUProfile(f)
		defer f.Close()
		defer pprof.StopCPUProfile()
	}

	// Write mem profile if requested.
	if cfg.MemProfile != "" {
		f, err := os.Create(cfg.MemProfile)
		if err != nil {
			dcrdLog.Errorf("Unable to create mem profile: %v", err)
			return err
		}
		defer f.Close()
		defer pprof.WriteHeapProfile(f)
	}

	var lifetimeNotifier lifetimeEventServer
	if cfg.LifetimeEvents {
		lifetimeNotifier = newLifetimeEventServer(outgoingPipeMessages)
	}

	if cfg.PipeRx != 0 {
		go serviceControlPipeRx(uintptr(cfg.PipeRx))
	}
	if cfg.PipeTx != 0 {
		go serviceControlPipeTx(uintptr(cfg.PipeTx))
	} else {
		go drainOutgoingPipeMessages()
	}

	// Return now if a shutdown signal was triggered.
	if shutdownRequested(ctx) {
		return nil
	}

	// Load the block database.
	lifetimeNotifier.notifyStartupEvent(lifetimeEventDBOpen)
	db, err := loadBlockDB(cfg.params.Params)
	if err != nil {
		dcrdLog.Errorf("%v", err)
		return err
	}
	defer func() {
		// Ensure the database is sync'd and closed on shutdown.
		lifetimeNotifier.notifyShutdownEvent(lifetimeEventDBOpen)
		dcrdLog.Infof("Gracefully shutting down the database...")
		db.Close()
	}()

	// Return now if a shutdown signal was triggered.
	if shutdownRequested(ctx) {
		return nil
	}

	// Drop indexes and exit if requested.
	//
	// NOTE: The order is important here because dropping the tx index also
	// drops the address index since it relies on it.
	if cfg.DropAddrIndex {
		if err := indexers.DropAddrIndex(ctx, db); err != nil {
			dcrdLog.Errorf("%v", err)
			return err
		}

		return nil
	}
	if cfg.DropTxIndex {
		if err := indexers.DropTxIndex(ctx, db); err != nil {
			dcrdLog.Errorf("%v", err)
			return err
		}

		return nil
	}
	if cfg.DropExistsAddrIndex {
		if err := indexers.DropExistsAddrIndex(ctx, db); err != nil {
			dcrdLog.Errorf("%v", err)
			return err
		}

		return nil
	}
	if cfg.DropCFIndex {
		if err := indexers.DropCfIndex(ctx, db); err != nil {
			dcrdLog.Errorf("%v", err)
			return err
		}

		return nil
	}

	// Create server and start it.
	lifetimeNotifier.notifyStartupEvent(lifetimeEventP2PServer)
	svr, err := newServer(ctx, cfg.Listeners, db, cfg.params.Params,
		cfg.DataDir)
	if err != nil {
		dcrdLog.Errorf("Unable to start server: %v", err)
		return err
	}
	serverDone := make(chan struct{})
	defer func() {
		lifetimeNotifier.notifyShutdownEvent(lifetimeEventP2PServer)
		<-serverDone
		srvrLog.Infof("Server shutdown complete")
	}()
	go func(s *server) {
		s.Run(ctx)
		close(serverDone)
	}(svr)

	if shutdownRequested(ctx) {
		return nil
	}

	lifetimeNotifier.notifyStartupComplete()

	// Signal the Windows service (if running) that startup has completed.
	serviceStartOfDayChan <- cfg

	// Wait until the interrupt signal is received from an OS signal or
	// shutdown is requested through one of the subsystems such as the RPC
	// server.
	<-ctx.Done()
	return nil
}

func main() {
	// Use all processor cores.
	runtime.GOMAXPROCS(runtime.NumCPU())

	// Block and transaction processing can cause bursty allocations.  This
	// limits the garbage collector from excessively overallocating during
	// bursts.  This value was arrived at with the help of profiling live
	// usage.
	debug.SetGCPercent(20)

	// Up some limits.
	if err := limits.SetLimits(); err != nil {
		fmt.Fprintf(os.Stderr, "failed to set limits: %v\n", err)
		os.Exit(1)
	}

	// Call serviceMain on Windows to handle running as a service.  When
	// the return isService flag is true, exit now since we ran as a
	// service.  Otherwise, just fall through to normal operation.
	if runtime.GOOS == "windows" {
		isService, err := winServiceMain()
		if err != nil {
			fmt.Println(err)
			os.Exit(1)
		}
		if isService {
			os.Exit(0)
		}
	}

	// Work around defer not working after os.Exit()
	if err := dcrdMain(); err != nil {
		os.Exit(1)
	}
}
<commit_msg>main: Simplify startup logic slightly.<commit_after>// Copyright (c) 2013-2016 The btcsuite developers
// Copyright (c) 2015-2019 The Decred developers
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.

package main

import (
	"fmt"
	"net/http"
	_ "net/http/pprof"
	"os"
	"runtime"
	"runtime/debug"
	"runtime/pprof"

	"github.com/decred/dcrd/blockchain/v3/indexers"
	"github.com/decred/dcrd/internal/limits"
	"github.com/decred/dcrd/internal/version"
)

var cfg *config

// winServiceMain is only invoked on Windows.  It detects when dcrd is running
// as a service and reacts accordingly.
var winServiceMain func() (bool, error)

// serviceStartOfDayChan is only used by Windows when the code is running as a
// service.  It signals the service code that startup has completed.  Notice
// that it uses a buffered channel so the caller will not be blocked when the
// service is not running.
var serviceStartOfDayChan = make(chan *config, 1)

// dcrdMain is the real main function for dcrd.  It is necessary to work around
// the fact that deferred functions do not run when os.Exit() is called.
func dcrdMain() error {
	// Load configuration and parse command line.  This function also
	// initializes logging and configures it accordingly.
	tcfg, _, err := loadConfig()
	if err != nil {
		return err
	}
	cfg = tcfg
	defer func() {
		if logRotator != nil {
			logRotator.Close()
		}
	}()

	// Get a context that will be canceled when a shutdown signal has been
	// triggered either from an OS signal such as SIGINT (Ctrl+C) or from
	// another subsystem such as the RPC server.
	ctx := shutdownListener()
	defer dcrdLog.Info("Shutdown complete")

	// Show version and home dir at startup.
	dcrdLog.Infof("Version %s (Go version %s %s/%s)", version.String(),
		runtime.Version(), runtime.GOOS, runtime.GOARCH)
	dcrdLog.Infof("Home dir: %s", cfg.HomeDir)
	if cfg.NoFileLogging {
		dcrdLog.Info("File logging disabled")
	}

	// Enable http profiling server if requested.
	if cfg.Profile != "" {
		go func() {
			listenAddr := cfg.Profile
			dcrdLog.Infof("Creating profiling server "+
				"listening on %s", listenAddr)
			profileRedirect := http.RedirectHandler("/debug/pprof",
				http.StatusSeeOther)
			http.Handle("/", profileRedirect)
			err := http.ListenAndServe(listenAddr, nil)
			if err != nil {
				fatalf(err.Error())
			}
		}()
	}

	// Write cpu profile if requested.
	if cfg.CPUProfile != "" {
		f, err := os.Create(cfg.CPUProfile)
		if err != nil {
			dcrdLog.Errorf("Unable to create cpu profile: %v", err.Error())
			return err
		}
		pprof.StartCPUProfile(f)
		defer f.Close()
		defer pprof.StopCPUProfile()
	}

	// Write mem profile if requested.
	if cfg.MemProfile != "" {
		f, err := os.Create(cfg.MemProfile)
		if err != nil {
			dcrdLog.Errorf("Unable to create mem profile: %v", err)
			return err
		}
		defer f.Close()
		defer pprof.WriteHeapProfile(f)
	}

	var lifetimeNotifier lifetimeEventServer
	if cfg.LifetimeEvents {
		lifetimeNotifier = newLifetimeEventServer(outgoingPipeMessages)
	}

	if cfg.PipeRx != 0 {
		go serviceControlPipeRx(uintptr(cfg.PipeRx))
	}
	if cfg.PipeTx != 0 {
		go serviceControlPipeTx(uintptr(cfg.PipeTx))
	} else {
		go drainOutgoingPipeMessages()
	}

	// Return now if a shutdown signal was triggered.
	if shutdownRequested(ctx) {
		return nil
	}

	// Load the block database.
	lifetimeNotifier.notifyStartupEvent(lifetimeEventDBOpen)
	db, err := loadBlockDB(cfg.params.Params)
	if err != nil {
		dcrdLog.Errorf("%v", err)
		return err
	}
	defer func() {
		// Ensure the database is sync'd and closed on shutdown.
		lifetimeNotifier.notifyShutdownEvent(lifetimeEventDBOpen)
		dcrdLog.Infof("Gracefully shutting down the database...")
		db.Close()
	}()

	// Return now if a shutdown signal was triggered.
	if shutdownRequested(ctx) {
		return nil
	}

	// Drop indexes and exit if requested.
	//
	// NOTE: The order is important here because dropping the tx index also
	// drops the address index since it relies on it.
	if cfg.DropAddrIndex {
		if err := indexers.DropAddrIndex(ctx, db); err != nil {
			dcrdLog.Errorf("%v", err)
			return err
		}

		return nil
	}
	if cfg.DropTxIndex {
		if err := indexers.DropTxIndex(ctx, db); err != nil {
			dcrdLog.Errorf("%v", err)
			return err
		}

		return nil
	}
	if cfg.DropExistsAddrIndex {
		if err := indexers.DropExistsAddrIndex(ctx, db); err != nil {
			dcrdLog.Errorf("%v", err)
			return err
		}

		return nil
	}
	if cfg.DropCFIndex {
		if err := indexers.DropCfIndex(ctx, db); err != nil {
			dcrdLog.Errorf("%v", err)
			return err
		}

		return nil
	}

	// Create server.
	lifetimeNotifier.notifyStartupEvent(lifetimeEventP2PServer)
	svr, err := newServer(ctx, cfg.Listeners, db, cfg.params.Params,
		cfg.DataDir)
	if err != nil {
		dcrdLog.Errorf("Unable to start server: %v", err)
		return err
	}

	if shutdownRequested(ctx) {
		return nil
	}

	lifetimeNotifier.notifyStartupComplete()
	defer lifetimeNotifier.notifyShutdownEvent(lifetimeEventP2PServer)

	// Signal the Windows service (if running) that startup has completed.
	serviceStartOfDayChan <- cfg

	// Run the server.  This will block until the context is cancelled which
	// happens when the interrupt signal is received from an OS signal or
	// shutdown is requested through one of the subsystems such as the RPC
	// server.
	svr.Run(ctx)
	srvrLog.Infof("Server shutdown complete")
	return nil
}

func main() {
	// Use all processor cores.
	runtime.GOMAXPROCS(runtime.NumCPU())

	// Block and transaction processing can cause bursty allocations.  This
	// limits the garbage collector from excessively overallocating during
	// bursts.  This value was arrived at with the help of profiling live
	// usage.
	debug.SetGCPercent(20)

	// Up some limits.
	if err := limits.SetLimits(); err != nil {
		fmt.Fprintf(os.Stderr, "failed to set limits: %v\n", err)
		os.Exit(1)
	}

	// Call serviceMain on Windows to handle running as a service.  When
	// the return isService flag is true, exit now since we ran as a
	// service.  Otherwise, just fall through to normal operation.
	if runtime.GOOS == "windows" {
		isService, err := winServiceMain()
		if err != nil {
			fmt.Println(err)
			os.Exit(1)
		}
		if isService {
			os.Exit(0)
		}
	}

	// Work around defer not working after os.Exit()
	if err := dcrdMain(); err != nil {
		os.Exit(1)
	}
}
<|endoftext|>


<commit_before>package cli

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

	"github.com/ipfs/go-ipfs/commands"
)

type kvs map[string]interface{}
type words []string

func sameWords(a words, b words) bool {
	if len(a) != len(b) {
		return false
	}
	for i, w := range a {
		if w != b[i] {
			return false
		}
	}
	return true
}

func sameKVs(a kvs, b kvs) bool {
	if len(a) != len(b) {
		return false
	}
	for k, v := range a {
		if v != b[k] {
			return false
		}
	}
	return true
}

func TestSameWords(t *testing.T) {
	a := []string{"v1", "v2"}
	b := []string{"v1", "v2", "v3"}
	c := []string{"v2", "v3"}
	d := []string{"v2"}
	e := []string{"v2", "v3"}
	f := []string{"v2", "v1"}

	test := func(a words, b words, v bool) {
		if sameWords(a, b) != v {
			t.Errorf("sameWords('%v', '%v') != %v", a, b, v)
		}
	}

	test(a, b, false)
	test(a, a, true)
	test(a, c, false)
	test(b, c, false)
	test(c, d, false)
	test(c, e, true)
	test(b, e, false)
	test(a, b, false)
	test(a, f, false)
	test(e, f, false)
	test(f, f, true)
}

func TestOptionParsing(t *testing.T) {
	subCmd := &commands.Command{}
	cmd := &commands.Command{
		Options: []commands.Option{
			commands.StringOption("string", "s", "a string"),
			commands.BoolOption("bool", "b", "a bool"),
		},
		Subcommands: map[string]*commands.Command{
			"test": subCmd,
		},
	}

	testHelper := func(args string, expectedOpts kvs, expectedWords words, expectErr bool) {
		_, opts, input, _, err := parseOpts(strings.Split(args, " "), cmd)
		if expectErr {
			if err == nil {
				t.Errorf("Command line '%v' parsing should have failed", args)
			}
		} else if err != nil {
			t.Errorf("Command line '%v' failed to parse: %v", args, err)
		} else if !sameWords(input, expectedWords) || !sameKVs(opts, expectedOpts) {
			t.Errorf("Command line '%v':\n  parsed as  %v %v\n  instead of %v %v",
				args, opts, input, expectedOpts, expectedWords)
		}
	}

	testFail := func(args string) {
		testHelper(args, kvs{}, words{}, true)
	}

	test := func(args string, expectedOpts kvs, expectedWords words) {
		testHelper(args, expectedOpts, expectedWords, false)
	}

	test("-", kvs{}, words{"-"})
	testFail("-b -b")
	test("beep boop", kvs{}, words{"beep", "boop"})
	test("test beep boop", kvs{}, words{"beep", "boop"})
	testFail("-s")
	test("-s foo", kvs{"s": "foo"}, words{})
	test("-sfoo", kvs{"s": "foo"}, words{})
	test("-s=foo", kvs{"s": "foo"}, words{})
	test("-b", kvs{"b": ""}, words{})
	test("-bs foo", kvs{"b": "", "s": "foo"}, words{})
	test("-sb", kvs{"s": "b"}, words{})
	test("-b foo", kvs{"b": ""}, words{"foo"})
	test("--bool foo", kvs{"bool": ""}, words{"foo"})
	testFail("--bool=foo")
	testFail("--string")
	test("--string foo", kvs{"string": "foo"}, words{})
	test("--string=foo", kvs{"string": "foo"}, words{})
	test("-- -b", kvs{}, words{"-b"})
	test("foo -b", kvs{"b": ""}, words{"foo"})
}

func TestArgumentParsing(t *testing.T) {
	rootCmd := &commands.Command{
		Subcommands: map[string]*commands.Command{
			"noarg": &commands.Command{},
			"onearg": &commands.Command{
				Arguments: []commands.Argument{
					commands.StringArg("a", true, false, "some arg"),
				},
			},
			"twoargs": &commands.Command{
				Arguments: []commands.Argument{
					commands.StringArg("a", true, false, "some arg"),
					commands.StringArg("b", true, false, "another arg"),
				},
			},
			"variadic": &commands.Command{
				Arguments: []commands.Argument{
					commands.StringArg("a", true, true, "some arg"),
				},
			},
			"optional": &commands.Command{
				Arguments: []commands.Argument{
					commands.StringArg("b", false, true, "another arg"),
				},
			},
			"reversedoptional": &commands.Command{
				Arguments: []commands.Argument{
					commands.StringArg("a", false, false, "some arg"),
					commands.StringArg("b", true, false, "another arg"),
				},
			},
			"stdinenabled": &commands.Command{
				Arguments: []commands.Argument{
					commands.StringArg("a", true, true, "some arg").EnableStdin(),
				},
			},
		},
	}

	_, _, _, err := Parse([]string{"noarg"}, nil, rootCmd)
	if err != nil {
		t.Error("Should have passed")
	}
	_, _, _, err = Parse([]string{"noarg", "value!"}, nil, rootCmd)
	if err == nil {
		t.Error("Should have failed (provided an arg, but command didn't define any)")
	}

	_, _, _, err = Parse([]string{"onearg", "value!"}, nil, rootCmd)
	if err != nil {
		t.Error("Should have passed")
	}
	_, _, _, err = Parse([]string{"onearg"}, nil, rootCmd)
	if err == nil {
		t.Error("Should have failed (didn't provide any args, arg is required)")
	}

	_, _, _, err = Parse([]string{"twoargs", "value1", "value2"}, nil, rootCmd)
	if err != nil {
		t.Error("Should have passed")
	}
	_, _, _, err = Parse([]string{"twoargs", "value!"}, nil, rootCmd)
	if err == nil {
		t.Error("Should have failed (only provided 1 arg, needs 2)")
	}
	_, _, _, err = Parse([]string{"twoargs"}, nil, rootCmd)
	if err == nil {
		t.Error("Should have failed (didn't provide any args, 2 required)")
	}

	_, _, _, err = Parse([]string{"variadic", "value!"}, nil, rootCmd)
	if err != nil {
		t.Error("Should have passed")
	}
	_, _, _, err = Parse([]string{"variadic", "value1", "value2", "value3"}, nil, rootCmd)
	if err != nil {
		t.Error("Should have passed")
	}
	_, _, _, err = Parse([]string{"variadic"}, nil, rootCmd)
	if err == nil {
		t.Error("Should have failed (didn't provide any args, 1 required)")
	}

	_, _, _, err = Parse([]string{"optional", "value!"}, nil, rootCmd)
	if err != nil {
		t.Error("Should have passed")
	}
	_, _, _, err = Parse([]string{"optional"}, nil, rootCmd)
	if err != nil {
		t.Error("Should have passed")
	}

	_, _, _, err = Parse([]string{"reversedoptional", "value1", "value2"}, nil, rootCmd)
	if err != nil {
		t.Error("Should have passed")
	}
	_, _, _, err = Parse([]string{"reversedoptional", "value!"}, nil, rootCmd)
	if err != nil {
		t.Error("Should have passed")
	}
	_, _, _, err = Parse([]string{"reversedoptional"}, nil, rootCmd)
	if err == nil {
		t.Error("Should have failed (didn't provide any args, 1 required)")
	}
	_, _, _, err = Parse([]string{"reversedoptional", "value1", "value2", "value3"}, nil, rootCmd)
	if err == nil {
		t.Error("Should have failed (provided too many args, only takes 1)")
	}

	// Use a temp file to simulate stdin
	fstdin, err := ioutil.TempFile("", "")
	if err != nil {
		t.Fatal(err)
	}
	defer os.Remove(fstdin.Name())

	if _, err := io.WriteString(fstdin, "stdin1"); err != nil {
		t.Fatal(err)
	}

	_, _, _, err = Parse([]string{"stdinenabled", "value1", "value2"}, nil, rootCmd)
	if err != nil {
		t.Error("Should have passed")
		t.Fatal(err)
	}
	_, _, _, err = Parse([]string{"stdinenabled"}, fstdin, rootCmd)
	if err != nil {
		t.Error("Should have passed")
		t.Fatal(err)
	}
	_, _, _, err = Parse([]string{"stdinenabled", "value1"}, fstdin, rootCmd)
	if err != nil {
		t.Error("Should have passed")
		t.Fatal(err)
	}
}
<commit_msg>parse_test: improve tests with stdin enabled arg<commit_after>package cli

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

	"github.com/ipfs/go-ipfs/commands"
)

type kvs map[string]interface{}
type words []string

func sameWords(a words, b words) bool {
	if len(a) != len(b) {
		return false
	}
	for i, w := range a {
		if w != b[i] {
			return false
		}
	}
	return true
}

func sameKVs(a kvs, b kvs) bool {
	if len(a) != len(b) {
		return false
	}
	for k, v := range a {
		if v != b[k] {
			return false
		}
	}
	return true
}

func TestSameWords(t *testing.T) {
	a := []string{"v1", "v2"}
	b := []string{"v1", "v2", "v3"}
	c := []string{"v2", "v3"}
	d := []string{"v2"}
	e := []string{"v2", "v3"}
	f := []string{"v2", "v1"}

	test := func(a words, b words, v bool) {
		if sameWords(a, b) != v {
			t.Errorf("sameWords('%v', '%v') != %v", a, b, v)
		}
	}

	test(a, b, false)
	test(a, a, true)
	test(a, c, false)
	test(b, c, false)
	test(c, d, false)
	test(c, e, true)
	test(b, e, false)
	test(a, b, false)
	test(a, f, false)
	test(e, f, false)
	test(f, f, true)
}

func TestOptionParsing(t *testing.T) {
	subCmd := &commands.Command{}
	cmd := &commands.Command{
		Options: []commands.Option{
			commands.StringOption("string", "s", "a string"),
			commands.BoolOption("bool", "b", "a bool"),
		},
		Subcommands: map[string]*commands.Command{
			"test": subCmd,
		},
	}

	testHelper := func(args string, expectedOpts kvs, expectedWords words, expectErr bool) {
		_, opts, input, _, err := parseOpts(strings.Split(args, " "), cmd)
		if expectErr {
			if err == nil {
				t.Errorf("Command line '%v' parsing should have failed", args)
			}
		} else if err != nil {
			t.Errorf("Command line '%v' failed to parse: %v", args, err)
		} else if !sameWords(input, expectedWords) || !sameKVs(opts, expectedOpts) {
			t.Errorf("Command line '%v':\n  parsed as  %v %v\n  instead of %v %v",
				args, opts, input, expectedOpts, expectedWords)
		}
	}

	testFail := func(args string) {
		testHelper(args, kvs{}, words{}, true)
	}

	test := func(args string, expectedOpts kvs, expectedWords words) {
		testHelper(args, expectedOpts, expectedWords, false)
	}

	test("-", kvs{}, words{"-"})
	testFail("-b -b")
	test("beep boop", kvs{}, words{"beep", "boop"})
	test("test beep boop", kvs{}, words{"beep", "boop"})
	testFail("-s")
	test("-s foo", kvs{"s": "foo"}, words{})
	test("-sfoo", kvs{"s": "foo"}, words{})
	test("-s=foo", kvs{"s": "foo"}, words{})
	test("-b", kvs{"b": ""}, words{})
	test("-bs foo", kvs{"b": "", "s": "foo"}, words{})
	test("-sb", kvs{"s": "b"}, words{})
	test("-b foo", kvs{"b": ""}, words{"foo"})
	test("--bool foo", kvs{"bool": ""}, words{"foo"})
	testFail("--bool=foo")
	testFail("--string")
	test("--string foo", kvs{"string": "foo"}, words{})
	test("--string=foo", kvs{"string": "foo"}, words{})
	test("-- -b", kvs{}, words{"-b"})
	test("foo -b", kvs{"b": ""}, words{"foo"})
}

func TestArgumentParsing(t *testing.T) {
	rootCmd := &commands.Command{
		Subcommands: map[string]*commands.Command{
			"noarg": &commands.Command{},
			"onearg": &commands.Command{
				Arguments: []commands.Argument{
					commands.StringArg("a", true, false, "some arg"),
				},
			},
			"twoargs": &commands.Command{
				Arguments: []commands.Argument{
					commands.StringArg("a", true, false, "some arg"),
					commands.StringArg("b", true, false, "another arg"),
				},
			},
			"variadic": &commands.Command{
				Arguments: []commands.Argument{
					commands.StringArg("a", true, true, "some arg"),
				},
			},
			"optional": &commands.Command{
				Arguments: []commands.Argument{
					commands.StringArg("b", false, true, "another arg"),
				},
			},
			"reversedoptional": &commands.Command{
				Arguments: []commands.Argument{
					commands.StringArg("a", false, false, "some arg"),
					commands.StringArg("b", true, false, "another arg"),
				},
			},
			"stdinenabled": &commands.Command{
				Arguments: []commands.Argument{
					commands.StringArg("a", true, true, "some arg").EnableStdin(),
				},
			},
		},
	}

	_, _, _, err := Parse([]string{"noarg"}, nil, rootCmd)
	if err != nil {
		t.Error("Should have passed")
	}
	_, _, _, err = Parse([]string{"noarg", "value!"}, nil, rootCmd)
	if err == nil {
		t.Error("Should have failed (provided an arg, but command didn't define any)")
	}

	_, _, _, err = Parse([]string{"onearg", "value!"}, nil, rootCmd)
	if err != nil {
		t.Error("Should have passed")
	}
	_, _, _, err = Parse([]string{"onearg"}, nil, rootCmd)
	if err == nil {
		t.Error("Should have failed (didn't provide any args, arg is required)")
	}

	_, _, _, err = Parse([]string{"twoargs", "value1", "value2"}, nil, rootCmd)
	if err != nil {
		t.Error("Should have passed")
	}
	_, _, _, err = Parse([]string{"twoargs", "value!"}, nil, rootCmd)
	if err == nil {
		t.Error("Should have failed (only provided 1 arg, needs 2)")
	}
	_, _, _, err = Parse([]string{"twoargs"}, nil, rootCmd)
	if err == nil {
		t.Error("Should have failed (didn't provide any args, 2 required)")
	}

	_, _, _, err = Parse([]string{"variadic", "value!"}, nil, rootCmd)
	if err != nil {
		t.Error("Should have passed")
	}
	_, _, _, err = Parse([]string{"variadic", "value1", "value2", "value3"}, nil, rootCmd)
	if err != nil {
		t.Error("Should have passed")
	}
	_, _, _, err = Parse([]string{"variadic"}, nil, rootCmd)
	if err == nil {
		t.Error("Should have failed (didn't provide any args, 1 required)")
	}

	_, _, _, err = Parse([]string{"optional", "value!"}, nil, rootCmd)
	if err != nil {
		t.Error("Should have passed")
	}
	_, _, _, err = Parse([]string{"optional"}, nil, rootCmd)
	if err != nil {
		t.Error("Should have passed")
	}

	_, _, _, err = Parse([]string{"reversedoptional", "value1", "value2"}, nil, rootCmd)
	if err != nil {
		t.Error("Should have passed")
	}
	_, _, _, err = Parse([]string{"reversedoptional", "value!"}, nil, rootCmd)
	if err != nil {
		t.Error("Should have passed")
	}
	_, _, _, err = Parse([]string{"reversedoptional"}, nil, rootCmd)
	if err == nil {
		t.Error("Should have failed (didn't provide any args, 1 required)")
	}
	_, _, _, err = Parse([]string{"reversedoptional", "value1", "value2", "value3"}, nil, rootCmd)
	if err == nil {
		t.Error("Should have failed (provided too many args, only takes 1)")
	}

	// Use a temp file to simulate stdin
	fstdin, err := ioutil.TempFile("", "")
	if err != nil {
		t.Fatal(err)
	}
	defer os.Remove(fstdin.Name())

	if _, err := io.WriteString(fstdin, "stdin1"); err != nil {
		t.Fatal(err)
	}

	test := func(cmd words, f *os.File, res words) {
		if f != nil {
			if _, err := f.Seek(0, os.SEEK_SET); err != nil {
				t.Fatal(err)
			}
		}
		req, _, _, err := Parse(cmd, f, rootCmd)
		if err != nil {
			t.Error("Command '%v' should have passed parsing", cmd)
		}
		if !sameWords(req.Arguments(), res) {
			t.Errorf("Arguments parsed from '%v' are not '%v'", cmd, res)
		}
	}

	test([]string{"stdinenabled", "value1", "value2"}, nil, []string{"value1", "value2"})
	test([]string{"stdinenabled"}, fstdin, []string{"stdin1"})
	test([]string{"stdinenabled", "value1"}, fstdin, []string{"stdin1", "value1"})
	test([]string{"stdinenabled", "value1", "value2"}, fstdin, []string{"stdin1", "value1", "value2"})
}
<|endoftext|>


<commit_before>// Copyright 2015 Apcera Inc. All rights reserved.

package main

import (
	"flag"
	"fmt"
	"io/ioutil"
	"log"
	"strings"
	"sync"
	"time"

	"github.com/nats-io/go-nats-streaming"
	"github.com/nats-io/nats"
	"github.com/nats-io/nats/bench"
)

// Some sane defaults
const (
	DefaultNumMsgs            = 100000
	DefaultNumPubs            = 1
	DefaultNumSubs            = 0
	DefaultNumConns           = -1
	DefaultAsync              = false
	DefaultMessageSize        = 128
	DefaultIgnoreOld          = false
	DefaultMaxPubAcksInflight = 1000
	DefaultClientID           = "benchmark"
)

func usage() {
	log.Fatalf("Usage: stan-scale-test [-s server (%s)] [--tls] [-id CLIENT_ID] [-np NUM_PUBLISHERS] [-ns NUM_SUBSCRIBERS] [-n NUM_MSGS] [-ms MESSAGE_SIZE] [-nc NUMCONNS] [-csv csvfile] [-mpa MAX_NUMBER_OF_PUBLISHED_ACKS_INFLIGHT] [-io] [-a] <subject>\n", nats.DefaultURL)
}

var conns []*nats.Conn

func buildConns(count int, opts *nats.Options) (error){
	var err error
	conns = nil
	err = nil

	// make a conn pool to use
	if count < 0 {
		return nil
	}
	conns = make([]*nats.Conn, count)
	for i := 0; i < count; i++ {
		conns[i], err = opts.Connect()
	}
	return err
}

var currentConn int = 0

func getNextNatsConn() *nats.Conn {
	if conns == nil {
		return nil
	}
	if currentConn == len(conns) {
		currentConn = 0
	}
	nc := conns[currentConn]
	currentConn++

	return nc
}

var currentSubjCount int = 0
var useUniqueSubjects bool = false

func getNextSubject(baseSubject string, max int) string {
    if !useUniqueSubjects {
	    return baseSubject
    }
	rv := fmt.Sprintf("%s.%d", baseSubject, currentSubjCount)
	currentSubjCount++
	if currentSubjCount == max {
		currentSubjCount = 0
	}

	return rv
}

var benchmark *bench.Benchmark

func main() {
	var urls = flag.String("s", nats.DefaultURL, "The nats server URLs (separated by comma)")
	var tls = flag.Bool("tls", false, "Use TLS Secure Connection")
	var numConns = flag.Int("nc", DefaultNumConns, "Number of connections to use (default is publishers+subscribers)")
	var numPubs = flag.Int("np", DefaultNumPubs, "Number of Concurrent Publishers")
	var numSubs = flag.Int("ns", DefaultNumSubs, "Number of Concurrent Subscribers")
	var numMsgs = flag.Int("n", DefaultNumMsgs, "Number of Messages to Publish")
	var async = flag.Bool("a", DefaultAsync, "Async Message Publishing")
	var messageSize = flag.Int("ms", DefaultMessageSize, "Message Size in bytes.")
	var ignoreOld = flag.Bool("io", DefaultIgnoreOld, "Subscribers Ignore Old Messages")
	var maxPubAcks = flag.Int("mpa", DefaultMaxPubAcksInflight, "Max number of published acks in flight")
	var clientID = flag.String("id", DefaultClientID, "Benchmark process base client ID.")
	var csvFile = flag.String("csv", "", "Save bench data to csv file")
	var uniqueSubjs = flag.Bool("us", false, "Use unique subjects")

	log.SetFlags(0)
	flag.Usage = usage
	flag.Parse()

	args := flag.Args()
	if len(args) != 1 {
		usage()
	}

	useUniqueSubjects = *uniqueSubjs
	// Setup the option block
	opts := nats.DefaultOptions
	opts.Servers = strings.Split(*urls, ",")
	for i, s := range opts.Servers {
		opts.Servers[i] = strings.Trim(s, " ")
	}
	opts.Secure = *tls

	if err := buildConns(*numConns, &opts); err != nil {
		log.Fatal("Unable to create connections: %v", err)
	}

	benchmark = bench.NewBenchmark("NATS Streaming", *numSubs, *numPubs)

	var startwg sync.WaitGroup
	var donewg sync.WaitGroup

	donewg.Add(*numPubs + *numSubs)

	// Run Subscribers first
	startwg.Add(*numSubs)
	for i := 0; i < *numSubs; i++ {
		subID := fmt.Sprintf("%s-sub-%d", *clientID, i)
		go runSubscriber(&startwg, &donewg, opts, *numMsgs, *messageSize, *ignoreOld, subID, getNextSubject(args[0], *numSubs))
	}
	startwg.Wait()

	// Now Publishers
	startwg.Add(*numPubs)
	pubCounts := bench.MsgsPerClient(*numMsgs, *numPubs)
	for i := 0; i < *numPubs; i++ {
		pubID := fmt.Sprintf("%s-pub-%d", *clientID, i)
                go runPublisher(&startwg, &donewg, opts, pubCounts[i], *messageSize, *async, pubID, *maxPubAcks, args[0], *numSubs)
	}

	log.Printf("Starting benchmark [msgs=%d, msgsize=%d, pubs=%d, subs=%d]\n", *numMsgs, *messageSize, *numPubs, *numSubs)

	startwg.Wait()
	donewg.Wait()

	benchmark.Close()
	fmt.Print(benchmark.Report())

	if len(*csvFile) > 0 {
		csv := benchmark.CSV()
		ioutil.WriteFile(*csvFile, []byte(csv), 0644)
		fmt.Printf("Saved metric data in csv file %s\n", *csvFile)
	}
}

func publishMsgs(snc stan.Conn, msg []byte, async bool, numMsgs int, subj string) {
	var published int = 0

	if async {
		ch := make(chan bool)
		acb := func(lguid string, err error) {
			published++
			if published >= numMsgs {
				ch <- true
			}
		}
		for i := 0; i < numMsgs; i++ {
			_, err := snc.PublishAsync(subj, msg, acb)
			if err != nil {
				log.Fatal(err)
			}
		}
		<-ch
	} else {
		for i := 0; i < numMsgs; i++ {
			err := snc.Publish(subj, msg)
			if err != nil {
				log.Fatal(err)
			}
			published++
		}
	}

}

func runPublisher(startwg, donewg *sync.WaitGroup, opts nats.Options, numMsgs int, msgSize int, async bool, pubID string, maxPubAcksInflight int, subj string, numSubs int) {

	var snc stan.Conn
	var err error

	nc := getNextNatsConn()
	if nc == nil {
		snc, err = stan.Connect("test-cluster", pubID, stan.MaxPubAcksInflight(maxPubAcksInflight))
	} else {
		snc, err = stan.Connect("test-cluster", pubID,
			stan.MaxPubAcksInflight(maxPubAcksInflight), stan.NatsConn(nc))
	}
	if err != nil {
		log.Fatalf("Publisher %s can't connect: %v\n", pubID, err)
	}

	startwg.Done()

	var msg []byte
	if msgSize > 0 {
		msg = make([]byte, msgSize)
	}

	start := time.Now()

	if useUniqueSubjects {
		for i := 0; i < numSubs; i++ {
		publishMsgs(snc, msg, async, numMsgs, fmt.Sprintf("%s.%d",subj, i))
		}
	} else {
		publishMsgs(snc, msg, async, numMsgs, subj)
	}

	benchmark.AddPubSample(bench.NewSample(numMsgs, msgSize, start, time.Now(), snc.NatsConn()))
	snc.Close()
	donewg.Done()
}

func runSubscriber(startwg, donewg *sync.WaitGroup, opts nats.Options, numMsgs int, msgSize int, ignoreOld bool, subID, subj string) {
	var snc stan.Conn
	var err error

	nc := getNextNatsConn()
	if nc == nil {
		snc, err = stan.Connect("test-cluster", subID)
	} else {
		snc, err = stan.Connect("test-cluster", subID, stan.NatsConn(nc))
	}
	if err != nil {
		log.Fatalf("Subscriber %s can't connect: %v\n", subID, err)
	}

	ch := make(chan bool)
	start := time.Now()

	received := 0
	mcb := func(msg *stan.Msg) {
		received++
		if received >= numMsgs {
			ch <- true
		}
	}

	if ignoreOld {
		snc.Subscribe(subj, mcb)
	} else {
		snc.Subscribe(subj, mcb, stan.DeliverAllAvailable())
	}
	startwg.Done()

	<-ch
	benchmark.AddSubSample(bench.NewSample(numMsgs, msgSize, start, time.Now(), snc.NatsConn()))
	snc.Close()
	donewg.Done()
}
<commit_msg>Add locking<commit_after>// Copyright 2015 Apcera Inc. All rights reserved.

package main

import (
	"flag"
	"fmt"
	"io/ioutil"
	"log"
	"strings"
	"sync"
	"time"

	"github.com/nats-io/go-nats-streaming"
	"github.com/nats-io/nats"
	"github.com/nats-io/nats/bench"
)

// Some sane defaults
const (
	DefaultNumMsgs            = 100000
	DefaultNumPubs            = 1
	DefaultNumSubs            = 0
	DefaultNumConns           = -1
	DefaultAsync              = false
	DefaultMessageSize        = 128
	DefaultIgnoreOld          = false
	DefaultMaxPubAcksInflight = 1000
	DefaultClientID           = "benchmark"
)

func usage() {
	log.Fatalf("Usage: stan-scale-test [-s server (%s)] [--tls] [-id CLIENT_ID] [-np NUM_PUBLISHERS] [-ns NUM_SUBSCRIBERS] [-n NUM_MSGS] [-ms MESSAGE_SIZE] [-nc NUMCONNS] [-csv csvfile] [-mpa MAX_NUMBER_OF_PUBLISHED_ACKS_INFLIGHT] [-io] [-a] <subject>\n", nats.DefaultURL)
}

var conns []*nats.Conn

func buildConns(count int, opts *nats.Options) error {
	var err error
	conns = nil
	err = nil

	// make a conn pool to use
	if count < 0 {
		return nil
	}
	conns = make([]*nats.Conn, count)
	for i := 0; i < count; i++ {
		conns[i], err = opts.Connect()
	}
	return err
}

var currentConn int
var connLock sync.Mutex

func getNextNatsConn() *nats.Conn {
	connLock.Lock()

	if conns == nil {
		connLock.Unlock()
		return nil
	}
	if currentConn == len(conns) {
		currentConn = 0
	}
	nc := conns[currentConn]
	currentConn++

	connLock.Unlock()

	return nc
}

var currentSubjCount int = 0
var useUniqueSubjects bool = false

func getNextSubject(baseSubject string, max int) string {
	if !useUniqueSubjects {
		return baseSubject
	}
	rv := fmt.Sprintf("%s.%d", baseSubject, currentSubjCount)
	currentSubjCount++
	if currentSubjCount == max {
		currentSubjCount = 0
	}

	return rv
}

var benchmark *bench.Benchmark

func main() {
	var urls = flag.String("s", nats.DefaultURL, "The nats server URLs (separated by comma)")
	var tls = flag.Bool("tls", false, "Use TLS Secure Connection")
	var numConns = flag.Int("nc", DefaultNumConns, "Number of connections to use (default is publishers+subscribers)")
	var numPubs = flag.Int("np", DefaultNumPubs, "Number of Concurrent Publishers")
	var numSubs = flag.Int("ns", DefaultNumSubs, "Number of Concurrent Subscribers")
	var numMsgs = flag.Int("n", DefaultNumMsgs, "Number of Messages to Publish")
	var async = flag.Bool("a", DefaultAsync, "Async Message Publishing")
	var messageSize = flag.Int("ms", DefaultMessageSize, "Message Size in bytes.")
	var ignoreOld = flag.Bool("io", DefaultIgnoreOld, "Subscribers Ignore Old Messages")
	var maxPubAcks = flag.Int("mpa", DefaultMaxPubAcksInflight, "Max number of published acks in flight")
	var clientID = flag.String("id", DefaultClientID, "Benchmark process base client ID.")
	var csvFile = flag.String("csv", "", "Save bench data to csv file")
	var uniqueSubjs = flag.Bool("us", false, "Use unique subjects")

	log.SetFlags(0)
	flag.Usage = usage
	flag.Parse()

	args := flag.Args()
	if len(args) != 1 {
		usage()
	}

	useUniqueSubjects = *uniqueSubjs
	// Setup the option block
	opts := nats.DefaultOptions
	opts.Servers = strings.Split(*urls, ",")
	for i, s := range opts.Servers {
		opts.Servers[i] = strings.Trim(s, " ")
	}
	opts.Secure = *tls

	if err := buildConns(*numConns, &opts); err != nil {
		log.Fatal("Unable to create connections: %v", err)
	}

	benchmark = bench.NewBenchmark("NATS Streaming", *numSubs, *numPubs)

	var startwg sync.WaitGroup
	var donewg sync.WaitGroup

	donewg.Add(*numPubs + *numSubs)

	// Run Subscribers first
	startwg.Add(*numSubs)
	for i := 0; i < *numSubs; i++ {
		subID := fmt.Sprintf("%s-sub-%d", *clientID, i)
		go runSubscriber(&startwg, &donewg, opts, *numMsgs, *messageSize, *ignoreOld, subID, getNextSubject(args[0], *numSubs))
	}
	startwg.Wait()

	// Now Publishers
	startwg.Add(*numPubs)
	pubCounts := bench.MsgsPerClient(*numMsgs, *numPubs)
	for i := 0; i < *numPubs; i++ {
		pubID := fmt.Sprintf("%s-pub-%d", *clientID, i)
		go runPublisher(&startwg, &donewg, opts, pubCounts[i], *messageSize, *async, pubID, *maxPubAcks, args[0], *numSubs)
	}

	log.Printf("Starting benchmark [msgs=%d, msgsize=%d, pubs=%d, subs=%d]\n", *numMsgs, *messageSize, *numPubs, *numSubs)

	startwg.Wait()
	donewg.Wait()

	benchmark.Close()
	fmt.Print(benchmark.Report())

	if len(*csvFile) > 0 {
		csv := benchmark.CSV()
		ioutil.WriteFile(*csvFile, []byte(csv), 0644)
		fmt.Printf("Saved metric data in csv file %s\n", *csvFile)
	}
}

func publishMsgs(snc stan.Conn, msg []byte, async bool, numMsgs int, subj string) {
	var published int = 0

	if async {
		ch := make(chan bool)
		acb := func(lguid string, err error) {
			published++
			if published >= numMsgs {
				ch <- true
			}
		}
		for i := 0; i < numMsgs; i++ {
			_, err := snc.PublishAsync(subj, msg, acb)
			if err != nil {
				log.Fatal(err)
			}
		}
		<-ch
	} else {
		for i := 0; i < numMsgs; i++ {
			err := snc.Publish(subj, msg)
			if err != nil {
				log.Fatal(err)
			}
			published++
		}
	}

}

func runPublisher(startwg, donewg *sync.WaitGroup, opts nats.Options, numMsgs int, msgSize int, async bool, pubID string, maxPubAcksInflight int, subj string, numSubs int) {

	var snc stan.Conn
	var err error

	nc := getNextNatsConn()
	if nc == nil {
		snc, err = stan.Connect("test-cluster", pubID, stan.MaxPubAcksInflight(maxPubAcksInflight))
	} else {
		snc, err = stan.Connect("test-cluster", pubID,
			stan.MaxPubAcksInflight(maxPubAcksInflight), stan.NatsConn(nc))
	}
	if err != nil {
		log.Fatalf("Publisher %s can't connect: %v\n", pubID, err)
	}

	startwg.Done()

	var msg []byte
	if msgSize > 0 {
		msg = make([]byte, msgSize)
	}

	start := time.Now()

	if useUniqueSubjects {
		for i := 0; i < numSubs; i++ {
			publishMsgs(snc, msg, async, numMsgs, fmt.Sprintf("%s.%d", subj, i))
		}
	} else {
		publishMsgs(snc, msg, async, numMsgs, subj)
	}

	benchmark.AddPubSample(bench.NewSample(numMsgs, msgSize, start, time.Now(), snc.NatsConn()))
	snc.Close()
	donewg.Done()
}

func runSubscriber(startwg, donewg *sync.WaitGroup, opts nats.Options, numMsgs int, msgSize int, ignoreOld bool, subID, subj string) {
	var snc stan.Conn
	var err error

	nc := getNextNatsConn()
	if nc == nil {
		snc, err = stan.Connect("test-cluster", subID)
	} else {
		snc, err = stan.Connect("test-cluster", subID, stan.NatsConn(nc))
	}
	if err != nil {
		log.Fatalf("Subscriber %s can't connect: %v\n", subID, err)
	}

	ch := make(chan bool)
	start := time.Now()

	received := 0
	mcb := func(msg *stan.Msg) {
		received++
		if received >= numMsgs {
			ch <- true
		}
	}

	if ignoreOld {
		snc.Subscribe(subj, mcb)
	} else {
		snc.Subscribe(subj, mcb, stan.DeliverAllAvailable())
	}
	startwg.Done()

	<-ch
	benchmark.AddSubSample(bench.NewSample(numMsgs, msgSize, start, time.Now(), snc.NatsConn()))
	snc.Close()
	donewg.Done()
}
<|endoftext|>


<commit_before>package py

import (
	"fmt"
	. "github.com/smartystreets/goconvey/convey"
	"pfi/sensorbee/sensorbee/data"
	"testing"
)

func init() {
	Initialize()
}

func TestConvertGo2PyObject(t *testing.T) {
	Convey("Given an initialized python go2py test module", t, func() {
		ImportSysAndAppendPath("")

		mdl, err := LoadModule("_test_go2py")
		defer mdl.DecRef()
		So(err, ShouldBeNil)
		So(mdl, ShouldNotBeNil)

		type argAndExpected struct {
			arg      data.Value
			expected string
		}

		Convey("When set an object", func() {
			values := map[string]argAndExpected{
				"string": argAndExpected{data.String("test"), "test"},
				"int":    argAndExpected{data.Int(9), "9"},
				"float":  argAndExpected{data.Float(0.9), "0.9"},
				"byte":   argAndExpected{data.Blob([]byte("ABC")), "ABC"},
				"true":   argAndExpected{data.True, "True"},
				"false":  argAndExpected{data.False, "False"},
				"null":   argAndExpected{data.Null{}, "None"},
			}
			for k, v := range values {
				msg := fmt.Sprintf("Then function should return string value: %v", k)
				Convey(msg, func() {
					actual, err := mdl.Call("go2py_tostr", v.arg)
					So(err, ShouldBeNil)
					So(actual, ShouldEqual, v.expected)
				})
			}
		})

		Convey("When set map in map and map in array", func() {
			arg := data.Map{
				"string": data.String("test"),
				"map": data.Map{
					"instr": data.String("test2"),
				},
				"array": data.Array{
					data.String("array-test"), data.Int(55),
				},
			}
			actual, err := mdl.Call("go2py_mapinmap", arg)
			Convey("Then function should return valid values", func() {
				So(err, ShouldBeNil)
				So(actual, ShouldEqual, "test_test2_array-test_55")
			})
		})

		Convey("When set array in array and map", func() {
			arg := data.Array{
				data.Array{
					data.String("test"), data.Int(55),
				},
				data.Map{
					"map": data.String("inmap"),
				},
			}
			actual, err := mdl.Call("go2py_arrayinmap", arg)
			Convey("Then function should return valid values", func() {
				So(err, ShouldBeNil)
				So(actual, ShouldEqual, "test_55_inmap")
			})
		})
	})
}
<commit_msg>fix goconvey test<commit_after>package py

import (
	"fmt"
	. "github.com/smartystreets/goconvey/convey"
	"pfi/sensorbee/sensorbee/data"
	"testing"
)

func init() {
	Initialize()
}

func TestConvertGo2PyObject(t *testing.T) {
	Convey("Given an initialized python go2py test module", t, func() {
		ImportSysAndAppendPath("")

		mdl, err := LoadModule("_test_go2py")
		defer mdl.DecRef()
		So(err, ShouldBeNil)
		So(mdl, ShouldNotBeNil)

		type argAndExpected struct {
			arg      data.Value
			expected string
		}

		Convey("When set an object", func() {
			values := map[string]argAndExpected{
				"string": argAndExpected{data.String("test"), "test"},
				"int":    argAndExpected{data.Int(9), "9"},
				"float":  argAndExpected{data.Float(0.9), "0.9"},
				"byte":   argAndExpected{data.Blob([]byte("ABC")), "ABC"},
				"true":   argAndExpected{data.True, "True"},
				"false":  argAndExpected{data.False, "False"},
				"null":   argAndExpected{data.Null{}, "None"},
			}
			for k, v := range values {
				v := v
				msg := fmt.Sprintf("Then function should return string value: %v", k)
				Convey(msg, func() {
					actual, err := mdl.Call("go2py_tostr", v.arg)
					So(err, ShouldBeNil)
					So(actual, ShouldEqual, v.expected)
				})
			}
		})

		Convey("When set map in map and map in array", func() {
			arg := data.Map{
				"string": data.String("test"),
				"map": data.Map{
					"instr": data.String("test2"),
				},
				"array": data.Array{
					data.String("array-test"), data.Int(55),
				},
			}
			actual, err := mdl.Call("go2py_mapinmap", arg)
			Convey("Then function should return valid values", func() {
				So(err, ShouldBeNil)
				So(actual, ShouldEqual, "test_test2_array-test_55")
			})
		})

		Convey("When set array in array and map", func() {
			arg := data.Array{
				data.Array{
					data.String("test"), data.Int(55),
				},
				data.Map{
					"map": data.String("inmap"),
				},
			}
			actual, err := mdl.Call("go2py_arrayinmap", arg)
			Convey("Then function should return valid values", func() {
				So(err, ShouldBeNil)
				So(actual, ShouldEqual, "test_55_inmap")
			})
		})
	})
}
<|endoftext|>


<commit_before>package state

import (
	"github.com/campadrenalin/go-deje/broadcast"
	"sync"
)

type PrimitiveBroadcaster struct {
	*broadcast.Broadcaster
}

func NewPrimitiveBroadcaster() PrimitiveBroadcaster {
	return PrimitiveBroadcaster{
		broadcast.NewBroadcaster(),
	}
}

func (pb PrimitiveBroadcaster) Send(p Primitive) {
	pb.Broadcaster.Send(p)
}

func (pb PrimitiveBroadcaster) Subscribe() *PrimitiveSubscription {
	ps := PrimitiveSubscription{
		pb.Broadcaster.Subscribe(),
		make(chan Primitive),
		0,
	}
	go ps.run()
	return &ps
}

type PrimitiveSubscription struct {
	sub       broadcast.Subscription
	out       chan Primitive
	state_mut sync.Mutex
	sending   int // Number of items being sent
}

func (ps *PrimitiveSubscription) Out() <-chan Primitive {
	return ps.out
}
func (ps *PrimitiveSubscription) Len() int {
	return ps.sub.Len() + len(ps.out) + ps.sending
}

// Secret underlying goroutine to type-assert everything to
// Primitive. We know that everything is going to be Primitive,
// as long as it's sent through the Broadcaster, but we need
// the cast to present ps.out as a <-chan Primitive.
func (ps *PrimitiveSubscription) run() {
	input := ps.sub.Out()
	for {
		ps.state_mut.Lock()
		value, ok := <-input
		ps.sending = 1
		ps.state_mut.Unlock()

		if !ok {
			close(ps.out)
			return
		}
		ps.out <- value.(Primitive)
		ps.sending = 0
	}
}

/*
func (ps *PrimitiveSubscription) Close() {
    ps.sub.Close()
}
*/
<commit_msg>Update state/broadcast enough to make tests pass<commit_after>package state

import (
	"github.com/campadrenalin/go-deje/broadcast"
	"sync"
)

type PrimitiveBroadcaster struct {
	*broadcast.Broadcaster
}

func NewPrimitiveBroadcaster() PrimitiveBroadcaster {
	return PrimitiveBroadcaster{
		broadcast.NewBroadcaster(),
	}
}

func (pb PrimitiveBroadcaster) Send(p Primitive) {
	pb.Broadcaster.Send(p)
}

func (pb PrimitiveBroadcaster) Subscribe() *PrimitiveSubscription {
	ps := PrimitiveSubscription{
		pb.Broadcaster.Subscribe(),
		make(chan Primitive),
		new(sync.Mutex),
		0,
	}
	go ps.run()
	return &ps
}

type PrimitiveSubscription struct {
	sub       *broadcast.Subscription
	out       chan Primitive
	state_mut *sync.Mutex
	sending   int // Number of items being sent
}

func (ps *PrimitiveSubscription) Out() <-chan Primitive {
	return ps.out
}
func (ps *PrimitiveSubscription) Len() int {
	return ps.sub.Len() + len(ps.out) + ps.sending
}

// Secret underlying goroutine to type-assert everything to
// Primitive. We know that everything is going to be Primitive,
// as long as it's sent through the Broadcaster, but we need
// the cast to present ps.out as a <-chan Primitive.
func (ps *PrimitiveSubscription) run() {
	input := ps.sub.Out()
	for {
		ps.state_mut.Lock()
		value, ok := <-input
		ps.sending = 1
		ps.state_mut.Unlock()

		if !ok {
			close(ps.out)
			return
		}
		ps.out <- value.(Primitive)
		ps.sending = 0
	}
}

/*
func (ps *PrimitiveSubscription) Close() {
    ps.sub.Close()
}
*/
<|endoftext|>


<commit_before>package utils

import (
	"testing"

	"github.com/stretchr/testify/assert"
)

func TestRandomString(t *testing.T) {
	s1 := RandomString(10)
	assert.Equal(t, 10, len(s1))
	s2 := RandomString(10)
	assert.Equal(t, 10, len(s2))
	assert.NotEqual(t, s1, s2)
}

func TestTruncateID(t *testing.T) {
	r1 := TruncateID("1234")
	assert.Equal(t, r1, "1234")
	r2 := TruncateID("12345678")
	assert.Equal(t, r2, "1234567")
}

func TestTail(t *testing.T) {
	r1 := Tail("")
	assert.Equal(t, r1, "")
	r2 := Tail("/")
	assert.Equal(t, r2, "")
	r3 := Tail("a/b")
	assert.Equal(t, r3, "b")
	r4 := Tail("a/b/c")
	assert.Equal(t, r4, "c")
}

func TestGetGitRepoName(t *testing.T) {
	_, err := GetGitRepoName("xxx")
	assert.Error(t, err)

	_, err = GetGitRepoName("http://gitlab.ricebook.net/platform/core.git")
	assert.Error(t, err)

	r1, err := GetGitRepoName("git@gitlab.ricebook.net:platform/core.git")
	assert.NoError(t, err)
	assert.Equal(t, r1, "core")
}
<commit_msg>tests<commit_after>package utils

import (
	"fmt"
	"testing"

	"github.com/stretchr/testify/assert"
)

func TestRandomString(t *testing.T) {
	s1 := RandomString(10)
	assert.Equal(t, 10, len(s1))
	s2 := RandomString(10)
	assert.Equal(t, 10, len(s2))
	assert.NotEqual(t, s1, s2, fmt.Sprintf("s1: %s, s2: %s", s1, s2))
}

func TestTruncateID(t *testing.T) {
	r1 := TruncateID("1234")
	assert.Equal(t, r1, "1234")
	r2 := TruncateID("12345678")
	assert.Equal(t, r2, "1234567")
}

func TestTail(t *testing.T) {
	r1 := Tail("")
	assert.Equal(t, r1, "")
	r2 := Tail("/")
	assert.Equal(t, r2, "")
	r3 := Tail("a/b")
	assert.Equal(t, r3, "b")
	r4 := Tail("a/b/c")
	assert.Equal(t, r4, "c")
}

func TestGetGitRepoName(t *testing.T) {
	_, err := GetGitRepoName("xxx")
	assert.Error(t, err)

	_, err = GetGitRepoName("http://gitlab.ricebook.net/platform/core.git")
	assert.Error(t, err)

	r1, err := GetGitRepoName("git@gitlab.ricebook.net:platform/core.git")
	assert.NoError(t, err)
	assert.Equal(t, r1, "core")
}
<|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.
//
// 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 SetMinLogLevel doc<commit_after>// 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)
}
<|endoftext|>


<commit_before>package negroni

import (
	"bytes"

	"log"
	"net/http"
	"os"
	"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())
}
<commit_msg>Use correct variable in logger.SetFormat call<commit_after>package negroni

import (
	"bytes"

	"log"
	"net/http"
	"os"
	"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(LoggerDefaultFormat)
	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 xlog

import (
	"log"
	"os"
	"fmt"
	"io"
)

// DefaultDateFormat is the date format to use when none has been specified.
const DefaultDateFormat = "2006-01-02 15:04:05.000"

// DefaultMessageFormat is the message format to use when none has been specified.
const DefaultMessageFormat = "{date|" + DefaultDateFormat + "} {name}.{level} {message}"

// Level describes a logging level.
type Level int

const (
	Debug Level = 1 << iota
	Info        = 1 << iota
	Notice      = 1 << iota
	Warning     = 1 << iota
	Error       = 1 << iota
	Critical    = 1 << iota
	Alert       = 1 << iota
	Emergency   = 1 << iota
)

// Levels maps Level to a string representation.
var Levels = map[Level]string{
	Debug: "DEBUG",
	Info: "INFO",
	Notice: "NOTICE",
	Warning: "WARNING",
	Error: "ERROR",
	Critical: "CRITICAL",
	Alert: "ALERT",
	Emergency: "EMERGENCY",
}

// FileAliases maps file aliases to real file pointers.
var FileAliases = map[string]*os.File{
	"stdout": os.Stdout,
	"stdin": os.Stdin,
	"stderr": os.Stderr,
}

var (
	// FileFlags defines the file open options.
	FileFlags int = os.O_RDWR|os.O_CREATE | os.O_APPEND

	// FileMode defines the mode files are opened in.
	FileMode os.FileMode = 0666

	// PanicOnFileErrors defines whether the logger should panic when opening a file
	// fails. When set to false, any file open errors are ignored, and the file won't be
	// appended.
	PanicOnFileErrors = true

	// LoggerCapacity defines the initial capacity for each type of logger.
	LoggerCapacity = 2
)

// Loggable is an interface that provides methods for logging messages to
// various levels.
type Loggable interface {
	Log(level Level, v ...interface{})
	Logf(level Level, format string, v ...interface{})
	Debug(v ...interface{})
	Debugf(format string, v ...interface{})
	Info(v ...interface{})
	Infof(format string, v ...interface{})
	Warning(v ...interface{})
	Warningf(format string, v ...interface{})
	Error(v ...interface{})
	Errorf(format string, v ...interface{})
	Critical(v ...interface{})
	Criticalf(format string, v ...interface{})
	Alert(v ...interface{})
	Alertf(format string, v ...interface{})
	Emergency(v ...interface{})
	Emergencyf(format string, v ...interface{})
}

// Logger is a light weight logger designed to write to multiple files at different
// log levels.
type Logger struct {
	// Enabled defines whether logging is enabled.
	Enabled  bool

	// Formatter is used to format the log messages.
	Formatter Formatter

	// Loggers holds the appended file loggers.
	Loggers LoggerMap

	// FatalOn represents levels that causes the application to exit.
	FatalOn Level

	// PanicOn represents levels that causes the application to panic.
	PanicOn Level

	// pointers contains any files that have been opened for logging.
	pointers []*os.File

	// closed defines whether the logger has been closed.
	closed bool
}

// NewLogger returns a *Logger instance that's been initialized with default values.
func NewLogger(name string) *Logger {
	return &Logger{
		Enabled: true,
		Formatter: NewDefaultFormatter(DefaultMessageFormat, name),
		Loggers: NewDefaultLoggerMap(),
		FatalOn: 0,
		PanicOn: 0,
		pointers: make([]*os.File, 0),
		closed: false,
	}
}

// NewFormattedLogger returns a *Logger instance using the provided formatter.
func NewFormattedLogger(formatter Formatter) *Logger {
	return &Logger{
		Enabled: true,
		Formatter: formatter,
		Loggers: NewDefaultLoggerMap(),
		FatalOn: 0,
		PanicOn: 0,
		pointers: make([]*os.File, 0),
		closed: false,
	}
}

// Append adds a file that will be written to at the given level or greater.
// The file argument may be either the full path to a system file, or one of the
// aliases "stdout", "stdin", or "stderr".
func (l *Logger) Append(file string, level Level) {
	if w, ok := FileAliases[file]; ok {
		l.Loggers.Append(newLogger(w), level)
	} else {
		w := l.open(file)
		if w != nil {
			l.Loggers.Append(newLogger(w), level)
			l.pointers = append(l.pointers, w)
		}
	}
}

// MultiAppend adds one or more files to the logger.
func (l *Logger) MultiAppend(files []string, level Level) {
	for _, file := range files {
		l.Append(file, level)
	}
}

// AppendWriter adds a writer that will be written to at the given level or greater.
func (l *Logger) AppendWriter(w io.Writer, level Level) {
	l.Loggers.Append(newLogger(w), level)
}

// MultiAppendWriter adds one or more io.Writer instances to the logger.
func (l *Logger) MultiAppendWriter(writers []io.Writer, level Level) {
	for _, writer := range writers {
		l.AppendWriter(writer, level)
	}
}

// Close disables logging and frees up resources used by the logger.
// Note this method only closes files opened by the logger. It's the user's
// responsibility to close files that were passed to the logger via the
// AppendWriter method.
func (l *Logger) Close() {
	if !l.closed {
		for _, pointer := range l.pointers {
			pointer.Close()
		}

		l.Enabled = false
		l.Loggers = nil
		l.pointers = nil
	}
}

// Writable returns true when logging is enabled, and the logger hasn't been closed.
func (l *Logger) Writable() bool {
	return l.Enabled && !l.closed
}

// Log writes the message to each logger appended at the given level or higher.
// Arguments are handled in the manner of fmt.Print.
func (l *Logger) Log(level Level, v ...interface{}) {
	if l.Writable() {
		message := l.Formatter.Format(level, v...)
		for _, logger := range l.Loggers.FindByLevel(level) {
			logger.Print(message)
		}

		if l.FatalOn&level > 0 {
			os.Exit(1)
		} else if l.PanicOn&level > 0 {
			panic(message)
		}
	}
}

// Log writes the message to each logger appended at the given level or higher.
// Arguments are handled in the manner of fmt.Printf.
func (l *Logger) Logf(level Level, format string, v ...interface{}) {
	l.Log(level, fmt.Sprintf(format, v...))
}

// Debug prints to each log file at the Debug level.
// Arguments are handled in the manner of fmt.Print.
func (l *Logger) Debug(v ...interface{}) {
	l.Log(Debug, v...)
}

// Debugf prints to each log file at the Debug level.
// Arguments are handled in the manner of fmt.Printf.
func (l *Logger) Debugf(format string, v ...interface{}) {
	l.Logf(Debug, format, v...)
}

// Info prints to each log file at the Info level.
// Arguments are handled in the manner of fmt.Print.
func (l *Logger) Info(v ...interface{}) {
	l.Log(Info, v...)
}

// Infof prints to each log file at the Info level.
// Arguments are handled in the manner of fmt.Printf.
func (l *Logger) Infof(format string, v ...interface{}) {
	l.Logf(Info, format, v...)
}

// Notice prints to each log file at the Notice level.
// Arguments are handled in the manner of fmt.Print.
func (l *Logger) Notice(v ...interface{}) {
	l.Log(Notice, v...)
}

// Noticef prints to each log file at the Notice level.
// Arguments are handled in the manner of fmt.Printf.
func (l *Logger) Noticef(format string, v ...interface{}) {
	l.Logf(Notice, format, v...)
}

// Warning prints to each log file at the Warning level.
// Arguments are handled in the manner of fmt.Print.
func (l *Logger) Warning(v ...interface{}) {
	l.Log(Warning, v...)
}

// Warningf prints to each log file at the Warning level.
// Arguments are handled in the manner of fmt.Printf.
func (l *Logger) Warningf(format string, v ...interface{}) {
	l.Logf(Warning, format, v...)
}

// Error prints to each log file at the Error level.
// Arguments are handled in the manner of fmt.Print.
func (l *Logger) Error(v ...interface{}) {
	l.Log(Error, v...)
}

// Errorf prints to each log file at the Error level.
// Arguments are handled in the manner of fmt.Printf.
func (l *Logger) Errorf(format string, v ...interface{}) {
	l.Logf(Error, format, v...)
}

// Critical prints to each log file at the Critical level.
// Arguments are handled in the manner of fmt.Print.
func (l *Logger) Critical(v ...interface{}) {
	l.Log(Critical, v...)
}

// Criticalf prints to each log file at the Critical level.
// Arguments are handled in the manner of fmt.Printf.
func (l *Logger) Criticalf(format string, v ...interface{}) {
	l.Logf(Critical, format, v...)
}

// Alert prints to each log file at the Alert level.
// Arguments are handled in the manner of fmt.Print.
func (l *Logger) Alert(v ...interface{}) {
	l.Log(Alert, v...)
}

// Alertf prints to each log file at the Alert level.
// Arguments are handled in the manner of fmt.Printf.
func (l *Logger) Alertf(format string, v ...interface{}) {
	l.Logf(Alert, format, v...)
}

// Emergency prints to each log file at the Emergency level.
// Arguments are handled in the manner of fmt.Print.
func (l *Logger) Emergency(v ...interface{}) {
	l.Log(Emergency, v...)
}

// Emergencyf prints to each log file at the Emergency level.
// Arguments are handled in the manner of fmt.Printf.
func (l *Logger) Emergencyf(format string, v ...interface{}) {
	l.Logf(Emergency, format, v...)
}

// open returns a file that logs can be written to.
func (l *Logger) open(name string) *os.File {
	w, err := os.OpenFile(name, FileFlags, FileMode)
	if err != nil {
		if PanicOnFileErrors {
			panic(err)
		} else {
			w = nil
		}
	}

	return w
}

// newLogger returns a *log.Logger instance configured with the default options.
func newLogger(w io.Writer) *log.Logger {
	return log.New(w, "", 0)
}
<commit_msg>Added NewMultiLogger() and NewMultiWriterLogger()<commit_after>package xlog

import (
	"log"
	"os"
	"fmt"
	"io"
)

// DefaultDateFormat is the date format to use when none has been specified.
const DefaultDateFormat = "2006-01-02 15:04:05.000"

// DefaultMessageFormat is the message format to use when none has been specified.
const DefaultMessageFormat = "{date|" + DefaultDateFormat + "} {name}.{level} {message}"

// Level describes a logging level.
type Level int

const (
	Debug Level = 1 << iota
	Info        = 1 << iota
	Notice      = 1 << iota
	Warning     = 1 << iota
	Error       = 1 << iota
	Critical    = 1 << iota
	Alert       = 1 << iota
	Emergency   = 1 << iota
)

// Levels maps Level to a string representation.
var Levels = map[Level]string{
	Debug: "DEBUG",
	Info: "INFO",
	Notice: "NOTICE",
	Warning: "WARNING",
	Error: "ERROR",
	Critical: "CRITICAL",
	Alert: "ALERT",
	Emergency: "EMERGENCY",
}

// FileAliases maps file aliases to real file pointers.
var FileAliases = map[string]*os.File{
	"stdout": os.Stdout,
	"stdin": os.Stdin,
	"stderr": os.Stderr,
}

var (
	// FileFlags defines the file open options.
	FileFlags int = os.O_RDWR|os.O_CREATE | os.O_APPEND

	// FileMode defines the mode files are opened in.
	FileMode os.FileMode = 0666

	// PanicOnFileErrors defines whether the logger should panic when opening a file
	// fails. When set to false, any file open errors are ignored, and the file won't be
	// appended.
	PanicOnFileErrors = true

	// LoggerCapacity defines the initial capacity for each type of logger.
	LoggerCapacity = 2
)

// Loggable is an interface that provides methods for logging messages to
// various levels.
type Loggable interface {
	Log(level Level, v ...interface{})
	Logf(level Level, format string, v ...interface{})
	Debug(v ...interface{})
	Debugf(format string, v ...interface{})
	Info(v ...interface{})
	Infof(format string, v ...interface{})
	Warning(v ...interface{})
	Warningf(format string, v ...interface{})
	Error(v ...interface{})
	Errorf(format string, v ...interface{})
	Critical(v ...interface{})
	Criticalf(format string, v ...interface{})
	Alert(v ...interface{})
	Alertf(format string, v ...interface{})
	Emergency(v ...interface{})
	Emergencyf(format string, v ...interface{})
}

// Logger is a light weight logger designed to write to multiple files at different
// log levels.
type Logger struct {
	// Enabled defines whether logging is enabled.
	Enabled  bool

	// Formatter is used to format the log messages.
	Formatter Formatter

	// Loggers holds the appended file loggers.
	Loggers LoggerMap

	// FatalOn represents levels that causes the application to exit.
	FatalOn Level

	// PanicOn represents levels that causes the application to panic.
	PanicOn Level

	// pointers contains any files that have been opened for logging.
	pointers []*os.File

	// closed defines whether the logger has been closed.
	closed bool
}

// NewLogger returns a *Logger instance that's been initialized with default values.
func NewLogger(name string) *Logger {
	return &Logger{
		Enabled: true,
		Formatter: NewDefaultFormatter(DefaultMessageFormat, name),
		Loggers: NewDefaultLoggerMap(),
		FatalOn: 0,
		PanicOn: 0,
		pointers: make([]*os.File, 0),
		closed: false,
	}
}

// NewMultiLogger returns a *Logger instance that's been initialized with one or
// more files at the given level.
func NewMultiLogger(name string, files []string, level Level) *Logger {
	logger := NewLogger(name)
	logger.MultiAppend(files, level);
	return logger;
}

// NewMultiWriterLogger returns a *Logger instance that's been initialized with one or
// more writers at the given level.
func NewMultiWriterLogger(name string, writers []io.Writer, level Level) *Logger {
	logger := NewLogger(name)
	logger.MultiAppendWriter(writers, level);
	return logger;
}

// NewFormattedLogger returns a *Logger instance using the provided formatter.
func NewFormattedLogger(formatter Formatter) *Logger {
	return &Logger{
		Enabled: true,
		Formatter: formatter,
		Loggers: NewDefaultLoggerMap(),
		FatalOn: 0,
		PanicOn: 0,
		pointers: make([]*os.File, 0),
		closed: false,
	}
}

// Append adds a file that will be written to at the given level or greater.
// The file argument may be either the full path to a system file, or one of the
// aliases "stdout", "stdin", or "stderr".
func (l *Logger) Append(file string, level Level) {
	if w, ok := FileAliases[file]; ok {
		l.Loggers.Append(newLogger(w), level)
	} else {
		w := l.open(file)
		if w != nil {
			l.Loggers.Append(newLogger(w), level)
			l.pointers = append(l.pointers, w)
		}
	}
}

// MultiAppend adds one or more files to the logger.
func (l *Logger) MultiAppend(files []string, level Level) {
	for _, file := range files {
		l.Append(file, level)
	}
}

// AppendWriter adds a writer that will be written to at the given level or greater.
func (l *Logger) AppendWriter(w io.Writer, level Level) {
	l.Loggers.Append(newLogger(w), level)
}

// MultiAppendWriter adds one or more io.Writer instances to the logger.
func (l *Logger) MultiAppendWriter(writers []io.Writer, level Level) {
	for _, writer := range writers {
		l.AppendWriter(writer, level)
	}
}

// Close disables logging and frees up resources used by the logger.
// Note this method only closes files opened by the logger. It's the user's
// responsibility to close files that were passed to the logger via the
// AppendWriter method.
func (l *Logger) Close() {
	if !l.closed {
		for _, pointer := range l.pointers {
			pointer.Close()
		}

		l.Enabled = false
		l.Loggers = nil
		l.pointers = nil
	}
}

// Writable returns true when logging is enabled, and the logger hasn't been closed.
func (l *Logger) Writable() bool {
	return l.Enabled && !l.closed
}

// Log writes the message to each logger appended at the given level or higher.
// Arguments are handled in the manner of fmt.Print.
func (l *Logger) Log(level Level, v ...interface{}) {
	if l.Writable() {
		message := l.Formatter.Format(level, v...)
		for _, logger := range l.Loggers.FindByLevel(level) {
			logger.Print(message)
		}

		if l.FatalOn&level > 0 {
			os.Exit(1)
		} else if l.PanicOn&level > 0 {
			panic(message)
		}
	}
}

// Log writes the message to each logger appended at the given level or higher.
// Arguments are handled in the manner of fmt.Printf.
func (l *Logger) Logf(level Level, format string, v ...interface{}) {
	l.Log(level, fmt.Sprintf(format, v...))
}

// Debug prints to each log file at the Debug level.
// Arguments are handled in the manner of fmt.Print.
func (l *Logger) Debug(v ...interface{}) {
	l.Log(Debug, v...)
}

// Debugf prints to each log file at the Debug level.
// Arguments are handled in the manner of fmt.Printf.
func (l *Logger) Debugf(format string, v ...interface{}) {
	l.Logf(Debug, format, v...)
}

// Info prints to each log file at the Info level.
// Arguments are handled in the manner of fmt.Print.
func (l *Logger) Info(v ...interface{}) {
	l.Log(Info, v...)
}

// Infof prints to each log file at the Info level.
// Arguments are handled in the manner of fmt.Printf.
func (l *Logger) Infof(format string, v ...interface{}) {
	l.Logf(Info, format, v...)
}

// Notice prints to each log file at the Notice level.
// Arguments are handled in the manner of fmt.Print.
func (l *Logger) Notice(v ...interface{}) {
	l.Log(Notice, v...)
}

// Noticef prints to each log file at the Notice level.
// Arguments are handled in the manner of fmt.Printf.
func (l *Logger) Noticef(format string, v ...interface{}) {
	l.Logf(Notice, format, v...)
}

// Warning prints to each log file at the Warning level.
// Arguments are handled in the manner of fmt.Print.
func (l *Logger) Warning(v ...interface{}) {
	l.Log(Warning, v...)
}

// Warningf prints to each log file at the Warning level.
// Arguments are handled in the manner of fmt.Printf.
func (l *Logger) Warningf(format string, v ...interface{}) {
	l.Logf(Warning, format, v...)
}

// Error prints to each log file at the Error level.
// Arguments are handled in the manner of fmt.Print.
func (l *Logger) Error(v ...interface{}) {
	l.Log(Error, v...)
}

// Errorf prints to each log file at the Error level.
// Arguments are handled in the manner of fmt.Printf.
func (l *Logger) Errorf(format string, v ...interface{}) {
	l.Logf(Error, format, v...)
}

// Critical prints to each log file at the Critical level.
// Arguments are handled in the manner of fmt.Print.
func (l *Logger) Critical(v ...interface{}) {
	l.Log(Critical, v...)
}

// Criticalf prints to each log file at the Critical level.
// Arguments are handled in the manner of fmt.Printf.
func (l *Logger) Criticalf(format string, v ...interface{}) {
	l.Logf(Critical, format, v...)
}

// Alert prints to each log file at the Alert level.
// Arguments are handled in the manner of fmt.Print.
func (l *Logger) Alert(v ...interface{}) {
	l.Log(Alert, v...)
}

// Alertf prints to each log file at the Alert level.
// Arguments are handled in the manner of fmt.Printf.
func (l *Logger) Alertf(format string, v ...interface{}) {
	l.Logf(Alert, format, v...)
}

// Emergency prints to each log file at the Emergency level.
// Arguments are handled in the manner of fmt.Print.
func (l *Logger) Emergency(v ...interface{}) {
	l.Log(Emergency, v...)
}

// Emergencyf prints to each log file at the Emergency level.
// Arguments are handled in the manner of fmt.Printf.
func (l *Logger) Emergencyf(format string, v ...interface{}) {
	l.Logf(Emergency, format, v...)
}

// open returns a file that logs can be written to.
func (l *Logger) open(name string) *os.File {
	w, err := os.OpenFile(name, FileFlags, FileMode)
	if err != nil {
		if PanicOnFileErrors {
			panic(err)
		} else {
			w = nil
		}
	}

	return w
}

// newLogger returns a *log.Logger instance configured with the default options.
func newLogger(w io.Writer) *log.Logger {
	return log.New(w, "", 0)
}
<|endoftext|>


<commit_before>package golog

import (
	"flag"
	"fmt"
	"os"
	"strconv"
)

var defaultMinLogLevel int = ERROR

// Logger.Log uses the level to determine whether or not to output the
// arguments. Logger.Log will output the provided arguments exactly, without
// additional formatting such as adding a prefix etc. In addition, Logger.Log
// must be thread safe. The FailNow() function flushes the Logger and performs
// some action. The action performed by FailNow() is deliberately unspecified,
// but could include os.Exit(1) or testing.(*T).FailNow(), etc.
type Logger interface {
	// If the message is to be logged, evaluates the closure and outputs
	// the result.
	Log(level int, closure func() *LogMessage)
	// Fail and halt standard control flow.
	FailNow()
	// All future calls to log with log only if the message is at
	// level or higher.
	// TODO(awreece) Put in different interface to keep Logger agnostic?
	SetMinLogLevel(level int)
}

// A Logger that can be used as a flag to set minloglevel. For example,
//	var myLogger LoggerFlag = NewDefaultLogger()
//
//	func init() {
//		flag.Var(myLogger, "minloglevel", "Log messages at or above "+
//			"this level")
//	}
type LoggerFlag interface {
	Logger
	flag.Value
}

func ExitError() {
	os.Exit(1)
}

// Construct a new Logger that writes any messages of level minloglevel or
// higher to the given LogOuter. Calls to Logger.FailNow() call the provided
// failFunc closure.
func NewLogger(outer LogOuter, minloglevel int, failFunc func()) LoggerFlag {
	return &loggerImpl{outer, minloglevel, failFunc}
}

// Return a default initialized log outer.
func NewDefaultLogger() LoggerFlag {
	return &loggerImpl{
		NewDefaultMultiLogOuter(),
		defaultMinLogLevel,
		ExitError,
	}
}

type loggerImpl struct {
	LogOuter
	minloglevel int
	failFunc    func()
}

func (l *loggerImpl) Log(level int, closure func() *LogMessage) {
	if level >= l.minloglevel {
		l.Output(closure())
	}
}

func (l *loggerImpl) FailNow() {
	// TODO Flush log outer?
	l.failFunc()
}

func (l *loggerImpl) SetMinLogLevel(level int) {
	l.minloglevel = level
}

func (l *loggerImpl) Set(val string) bool {
	if ival, err := strconv.Atoi(val); err != nil {
		l.minloglevel = ival
		return true
	} else {
		fmt.Println("Error setting flag: ", err)
	}

	return false
}

func (l *loggerImpl) String() string {
	return fmt.Sprint(l.minloglevel)
}
<commit_msg>Use correct equality for setting minloglevel<commit_after>package golog

import (
	"flag"
	"fmt"
	"os"
	"strconv"
)

var defaultMinLogLevel int = ERROR

// Logger.Log uses the level to determine whether or not to output the
// arguments. Logger.Log will output the provided arguments exactly, without
// additional formatting such as adding a prefix etc. In addition, Logger.Log
// must be thread safe. The FailNow() function flushes the Logger and performs
// some action. The action performed by FailNow() is deliberately unspecified,
// but could include os.Exit(1) or testing.(*T).FailNow(), etc.
type Logger interface {
	// If the message is to be logged, evaluates the closure and outputs
	// the result.
	Log(level int, closure func() *LogMessage)
	// Fail and halt standard control flow.
	FailNow()
	// All future calls to log with log only if the message is at
	// level or higher.
	// TODO(awreece) Put in different interface to keep Logger agnostic?
	SetMinLogLevel(level int)
}

// A Logger that can be used as a flag to set minloglevel. For example,
//	var myLogger LoggerFlag = NewDefaultLogger()
//
//	func init() {
//		flag.Var(myLogger, "minloglevel", "Log messages at or above "+
//			"this level")
//	}
type LoggerFlag interface {
	Logger
	flag.Value
}

func ExitError() {
	os.Exit(1)
}

// Construct a new Logger that writes any messages of level minloglevel or
// higher to the given LogOuter. Calls to Logger.FailNow() call the provided
// failFunc closure.
func NewLogger(outer LogOuter, minloglevel int, failFunc func()) LoggerFlag {
	return &loggerImpl{outer, minloglevel, failFunc}
}

// Return a default initialized log outer.
func NewDefaultLogger() LoggerFlag {
	return &loggerImpl{
		NewDefaultMultiLogOuter(),
		defaultMinLogLevel,
		ExitError,
	}
}

type loggerImpl struct {
	LogOuter
	minloglevel int
	failFunc    func()
}

func (l *loggerImpl) Log(level int, closure func() *LogMessage) {
	if level >= l.minloglevel {
		l.Output(closure())
	}
}

func (l *loggerImpl) FailNow() {
	// TODO Flush log outer?
	l.failFunc()
}

func (l *loggerImpl) SetMinLogLevel(level int) {
	l.minloglevel = level
}

func (l *loggerImpl) Set(val string) bool {
	if ival, err := strconv.Atoi(val); err == nil {
		l.minloglevel = ival
		return true
	} else {
		fmt.Println("Error setting flag: ", err)
	}

	return false
}

func (l *loggerImpl) String() string {
	return fmt.Sprint(l.minloglevel)
}
<|endoftext|>


<commit_before>/*
Copyright 2014 The Kubernetes Authors 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.
*/

package util

import (
	"io"
	"net/url"
	"strings"
)

// IsProbableEOF returns true if the given error resembles a connection termination
// scenario that would justify assuming that the watch is empty.
// These errors are what the Go http stack returns back to us which are general
// connection closure errors (strongly correlated) and callers that need to
// differentiate probable errors in connection behavior between normal "this is
// disconnected" should use the method.
func IsProbableEOF(err error) bool {
	if uerr, ok := err.(*url.Error); ok {
		err = uerr.Err
	}
	switch {
	case err == io.EOF:
		return true
	case err.Error() == "http: can't write HTTP request on broken connection":
		return true
	case strings.Contains(err.Error(), "connection reset by peer"):
		return true
	case strings.Contains(strings.ToLower(err.Error()), "use of closed network connection"):
		return true
	}
	return false
}
<commit_msg>UPSTREAM: 14967: Add util to set transport defaults<commit_after>/*
Copyright 2014 The Kubernetes Authors 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.
*/

package util

import (
	"io"
	"net/http"
	"net/url"
	"strings"
)

// IsProbableEOF returns true if the given error resembles a connection termination
// scenario that would justify assuming that the watch is empty.
// These errors are what the Go http stack returns back to us which are general
// connection closure errors (strongly correlated) and callers that need to
// differentiate probable errors in connection behavior between normal "this is
// disconnected" should use the method.
func IsProbableEOF(err error) bool {
	if uerr, ok := err.(*url.Error); ok {
		err = uerr.Err
	}
	switch {
	case err == io.EOF:
		return true
	case err.Error() == "http: can't write HTTP request on broken connection":
		return true
	case strings.Contains(err.Error(), "connection reset by peer"):
		return true
	case strings.Contains(strings.ToLower(err.Error()), "use of closed network connection"):
		return true
	}
	return false
}

var defaultTransport = http.DefaultTransport.(*http.Transport)

// SetTransportDefaults applies the defaults from http.DefaultTransport
// for the Proxy, Dial, and TLSHandshakeTimeout fields if unset
func SetTransportDefaults(t *http.Transport) *http.Transport {
	if t.Proxy == nil {
		t.Proxy = defaultTransport.Proxy
	}
	if t.Dial == nil {
		t.Dial = defaultTransport.Dial
	}
	if t.TLSHandshakeTimeout == 0 {
		t.TLSHandshakeTimeout = defaultTransport.TLSHandshakeTimeout
	}
	return t
}
<|endoftext|>


<commit_before>package gostardict

import (
	"compress/gzip"
	"io"
	"os"
	"strings"
)

// Dict implements in-memory dictionary
type Dict struct {
	buffer []byte
}

// GetSequence returns data at the given offset
func (d Dict) GetSequence(offset uint64, size uint64) []byte {
	return d.buffer[offset:(offset + size)]
}

// ReadDict reads dictionary into memory
func ReadDict(filename string, info *Info) (dict *Dict, err error) {
	reader, err := os.Open(filename)

	if err != nil {
		return
	}

	var r io.Reader

	if strings.HasSuffix(filename, ".dz") { // if file is compressed then read it from archive
		r, err = gzip.NewReader(reader)
	} else {
		r = reader
	}

	if err != nil {
		return
	}

	defer reader.Close()

	bufSize := 1024 * 16 // 16 KBytes
	p := make([]byte, bufSize, bufSize)

	var buffer []byte

	for {
		n, err := r.Read(p)

		if err != nil && err != io.EOF {
			panic(err)
		}
		if n == 0 {
			break
		}

		buffer = append(buffer, p[:n]...)
	}

	dict = new(Dict)
	dict.buffer = buffer

	return
}
<commit_msg>improved .dict file reading<commit_after>package gostardict

import (
	"compress/gzip"
	"io"
	"io/ioutil"
	"os"
	"strings"
)

// Dict implements in-memory dictionary
type Dict struct {
	buffer []byte
}

// GetSequence returns data at the given offset
func (d Dict) GetSequence(offset uint64, size uint64) []byte {
	return d.buffer[offset:(offset + size)]
}

// ReadDict reads dictionary into memory
func ReadDict(filename string, info *Info) (dict *Dict, err error) {
	reader, err := os.Open(filename)

	if err != nil {
		return
	}

	defer reader.Close()

	var r io.Reader

	if strings.HasSuffix(filename, ".dz") { // if file is compressed then read it from archive
		r, err = gzip.NewReader(reader)
	} else {
		r = reader
	}

	if err != nil {
		return
	}

	buffer, err := ioutil.ReadAll(r)

	dict = new(Dict)
	dict.buffer = buffer

	return
}
<|endoftext|>