<commit_before>/*
   Copyright 2017 Shlomi Noach, GitHub Inc.

   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 process

import (
	"sync"
	"time"

	"github.com/github/orchestrator/go/config"

	"github.com/github/orchestrator/go/raft"
	"github.com/openark/golib/log"
)

const registrationPollSeconds = 5

type NodeHealth struct {
	Hostname        string
	Token           string
	AppVersion      string
	FirstSeenActive string
	LastSeenActive  string
	ExtraInfo       string
	Command         string

	LastReported time.Time
	onceHistory  sync.Once
	onceUpdate   sync.Once
}

func NewNodeHealth() *NodeHealth {
	return &NodeHealth{
		Hostname:   ThisHostname,
		Token:      ProcessToken.Hash,
		AppVersion: config.RuntimeCLIFlags.ConfiguredVersion,
	}
}

func (nodeHealth *NodeHealth) Update() *NodeHealth {
	nodeHealth.onceUpdate.Do(func() {
		nodeHealth.Hostname = ThisHostname
		nodeHealth.Token = ProcessToken.Hash
		nodeHealth.AppVersion = config.RuntimeCLIFlags.ConfiguredVersion
	})
	nodeHealth.LastReported = time.Now()
	return nodeHealth
}

var ThisNodeHealth = NewNodeHealth()

type HealthStatus struct {
	Healthy        bool
	Hostname       string
	Token          string
	IsActiveNode   bool
	ActiveNode     NodeHealth
	Error          error
	AvailableNodes [](*NodeHealth)
}

type OrchestratorExecutionMode string

const (
	OrchestratorExecutionCliMode  OrchestratorExecutionMode = "CLIMode"
	OrchestratorExecutionHttpMode                           = "HttpMode"
)

var continuousRegistrationOnce sync.Once

func RegisterNode(nodeHealth *NodeHealth) (healthy bool, err error) {
	nodeHealth.Update()
	return WriteRegisterNode(nodeHealth)
}

// HealthTest attempts to write to the backend database and get a result
func HealthTest() (*HealthStatus, error) {
	health := HealthStatus{Healthy: false, Hostname: ThisHostname, Token: ProcessToken.Hash}

	healthy, err := RegisterNode(ThisNodeHealth)
	if err != nil {
		health.Error = err
		return &health, log.Errore(err)
	}
	health.Healthy = healthy
	if orcraft.IsRaftEnabled() {
		health.ActiveNode.Hostname = orcraft.GetLeader()
		health.IsActiveNode = orcraft.IsLeader()
	} else {
		health.ActiveNode, health.IsActiveNode, err = ElectedNode()
		if err != nil {
			health.Error = err
			return &health, log.Errore(err)
		}
	}

	health.AvailableNodes, err = ReadAvailableNodes(true)

	return &health, nil
}

// ContinuousRegistration will continuously update the node_health
// table showing that the current process is still running.
func ContinuousRegistration(extraInfo string, command string) {
	ThisNodeHealth.ExtraInfo = extraInfo
	ThisNodeHealth.Command = command
	continuousRegistrationOnce.Do(func() {
		tickOperation := func() {
			if _, err := RegisterNode(ThisNodeHealth); err != nil {
				log.Errorf("ContinuousRegistration: RegisterNode failed: %+v", err)
			}
		}
		// First one is synchronous
		tickOperation()
		go func() {
			registrationTick := time.Tick(time.Duration(registrationPollSeconds) * time.Second)
			for range registrationTick {
				// We already run inside a go-routine so
				// do not do this asynchronously.  If we
				// get stuck then we don't want to fill up
				// the backend pool with connections running
				// this maintenance operation.
				tickOperation()
			}
		}()
	})
}
<commit_msg>merging with master, resolving conflicts<commit_after>/*
   Copyright 2017 Shlomi Noach, GitHub Inc.

   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 process

import (
	"sync"
	"time"

	"github.com/github/orchestrator/go/config"

	"github.com/github/orchestrator/go/raft"
	"github.com/openark/golib/log"
)

const registrationPollSeconds = 5

type NodeHealth struct {
	Hostname        string
	Token           string
	AppVersion      string
	FirstSeenActive string
	LastSeenActive  string
	ExtraInfo       string
	Command         string
DBBackend       string

	LastReported time.Time
	onceHistory  sync.Once
	onceUpdate   sync.Once
}

func NewNodeHealth() *NodeHealth {
	return &NodeHealth{
		Hostname:   ThisHostname,
		Token:      ProcessToken.Hash,
		AppVersion: config.RuntimeCLIFlags.ConfiguredVersion,
	}
}

func (nodeHealth *NodeHealth) Update() *NodeHealth {
	nodeHealth.onceUpdate.Do(func() {
		nodeHealth.Hostname = ThisHostname
		nodeHealth.Token = ProcessToken.Hash
		nodeHealth.AppVersion = config.RuntimeCLIFlags.ConfiguredVersion
	})
	nodeHealth.LastReported = time.Now()
	return nodeHealth
}

var ThisNodeHealth = NewNodeHealth()

type HealthStatus struct {
	Healthy        bool
	Hostname       string
	Token          string
	IsActiveNode   bool
	ActiveNode     NodeHealth
	Error          error
	AvailableNodes [](*NodeHealth)
}

type OrchestratorExecutionMode string

const (
	OrchestratorExecutionCliMode  OrchestratorExecutionMode = "CLIMode"
	OrchestratorExecutionHttpMode                           = "HttpMode"
)

var continuousRegistrationOnce sync.Once

func RegisterNode(nodeHealth *NodeHealth) (healthy bool, err error) {
	nodeHealth.Update()
	return WriteRegisterNode(nodeHealth)
}

// HealthTest attempts to write to the backend database and get a result
func HealthTest() (*HealthStatus, error) {
	health := HealthStatus{Healthy: false, Hostname: ThisHostname, Token: ProcessToken.Hash}

	healthy, err := RegisterNode(ThisNodeHealth)
	if err != nil {
		health.Error = err
		return &health, log.Errore(err)
	}
	health.Healthy = healthy
	if orcraft.IsRaftEnabled() {
		health.ActiveNode.Hostname = orcraft.GetLeader()
		health.IsActiveNode = orcraft.IsLeader()
	} else {
		health.ActiveNode, health.IsActiveNode, err = ElectedNode()
		if err != nil {
			health.Error = err
			return &health, log.Errore(err)
		}
	}

	health.AvailableNodes, err = ReadAvailableNodes(true)

	return &health, nil
}

// ContinuousRegistration will continuously update the node_health
// table showing that the current process is still running.
func ContinuousRegistration(extraInfo string, command string) {
	ThisNodeHealth.ExtraInfo = extraInfo
	ThisNodeHealth.Command = command
	continuousRegistrationOnce.Do(func() {
		tickOperation := func() {
			if _, err := RegisterNode(ThisNodeHealth); err != nil {
				log.Errorf("ContinuousRegistration: RegisterNode failed: %+v", err)
			}
		}
		// First one is synchronous
		tickOperation()
		go func() {
			registrationTick := time.Tick(time.Duration(registrationPollSeconds) * time.Second)
			for range registrationTick {
				// We already run inside a go-routine so
				// do not do this asynchronously.  If we
				// get stuck then we don't want to fill up
				// the backend pool with connections running
				// this maintenance operation.
				tickOperation()
			}
		}()
	})
}
<|endoftext|>


<commit_before>package gobucket

import (
//  "net/http"
  "fmt"
)

func New(key string, pass string) *ApiClient {
  client := &ApiClient{}

  client.key = key
  client.pass = pass

  return client
}

type ApiClient struct {
  key string
  pass string
}

type Method int

const (
  GET Method = iota
  POST
  PUT
  DELETE
)

const baseUrl string = "https://bitbucket.org/api"

func (c *ApiClient) callV1(endpoint string, params map[string]string) {
  c.call("1.0", endpoint, params)
}

func (c *ApiClient) callV2(endpoint string, params map[string]string) {
  c.call("2.0", endpoint, params)
}

func (c *ApiClient) call(version string, endpoint string, params map[string]string) {
  url := fmt.Sprintf("%s/%s/%s", baseUrl, version, endpoint)

//  req, err := http.NewRequest("GET", "http://example.com", nil)

  fmt.Println(url)
}

func (c *ApiClient) GetRepositories(owner string) {
  c.callV2(fmt.Sprintf("repositories/%s", owner), nil)
}
<commit_msg>Make it actually run<commit_after>package gobucket

import (
//  "net/http"
  "fmt"
)

func New(key string, pass string) *ApiClient {
  client := &ApiClient{}

  client.key = key
  client.pass = pass

  return client
}

type ApiClient struct {
  key string
  pass string
}

type Method int

const (
  GET Method = iota
  POST
  PUT
  DELETE
)

const baseUrl string = "https://bitbucket.org/api"

func (c *ApiClient) callV1(endpoint string, params map[string]string) string {
  return c.call("1.0", endpoint, params)
}

func (c *ApiClient) callV2(endpoint string, params map[string]string) string {
  return c.call("2.0", endpoint, params)
}

func (c *ApiClient) call(version string, endpoint string, params map[string]string) string {
  url := fmt.Sprintf("%s/%s/%s", baseUrl, version, endpoint)

  return url
}

func (c *ApiClient) GetRepositories(owner string) string {
  return c.callV2(fmt.Sprintf("repositories/%s", owner), nil)
}
<|endoftext|>


<commit_before>package main

import (
	"github.com/marpaia/graphite-golang"
	"github.yandex-team.ru/mavlyutov/golagraphite"
	"gopkg.in/alecthomas/kingpin.v2"
)

var config = kingpin.Flag("config", "Path to yaml formatted config file.").Short('c').Required().ExistingFile()

func main() {

	kingpin.CommandLine.HelpFlag.Short('h')
	kingpin.Parse()

	config := golagraphite.NewConfig(*config)

	metrics_channel := make(chan []graphite.Metric, 1024)  // buffer of 1024 messages to survive graphite connection outages

	go golagraphite.SendPerfCounters(config, metrics_channel)
	go golagraphite.SendSQLStatements(config, metrics_channel)

	for metrics := range metrics_channel {
		golagraphite.SendMetrics(config.Graphite_settings.Hosts, metrics)
	}

}
<commit_msg>change package name<commit_after>package main

import (
	"github.com/marpaia/graphite-golang"
	"github.com/mavlyutov/golagraphite"
	"gopkg.in/alecthomas/kingpin.v2"
)

var config = kingpin.Flag("config", "Path to yaml formatted config file.").Short('c').Required().ExistingFile()

func main() {

	kingpin.CommandLine.HelpFlag.Short('h')
	kingpin.Parse()

	config := golagraphite.NewConfig(*config)

	metrics_channel := make(chan []graphite.Metric, 1024) // buffer of 1024 messages to survive graphite connection outages

	go golagraphite.SendPerfCounters(config, metrics_channel)
	go golagraphite.SendSQLStatements(config, metrics_channel)

	for metrics := range metrics_channel {
		golagraphite.SendMetrics(config.Graphite_settings.Hosts, metrics)
	}

}
<|endoftext|>


<commit_before>// mqtt
package mqtt

import (
	"encoding/json"
	"errors"
	"fmt"
	MQTT "git.eclipse.org/gitroot/paho/org.eclipse.paho.mqtt.golang.git"
	"time"
)

type Conn struct {
	opts   *MQTT.ClientOptions
	client *MQTT.Client
}

type Context struct {
	Payload []byte
	Error   error
}

type Handler func(c *Context)

func New(clientid string, conn string) *Conn {
	opts := MQTT.NewClientOptions().AddBroker(conn).SetClientID(clientid)
	return &Conn{
		opts: opts,
	}
}

func (t *Conn) Connect() error {
	t.client = MQTT.NewClient(t.opts)

	if token := t.client.Connect(); token.Wait() && token.Error() != nil {
		return token.Error()
	}
	return nil
}

func (t *Conn) Disconnect() {
	t.client.Disconnect(500)
}

func (t *Conn) On(topic string, h Handler) error {

	if token := t.client.Subscribe(topic, 0, func(client *MQTT.Client, m MQTT.Message) {
		ctx := new(Context)

		if !client.IsConnected() {
			ctx.Error = errors.New("Client not connected")
			h(ctx)
			return
		}
		client.Lock()
		ctx.Payload = m.Payload()
		h(ctx)

		client.Unlock()

	}); token.Wait() && token.Error() != nil {
		return token.Error()
	}

	return nil
}

func (t *Conn) Push(topic string, payload interface{}) error {
	buff, err := json.Marshal(payload)
	if err != nil {
		return err
	}
	token := t.client.Publish(topic, 0, false, buff)
	token.Wait()
	return token.Error()
}

func (t *Context) JSON(rcv interface{}) error {
	return json.Unmarshal(t.Payload, rcv)
}

<commit_msg>removed unused imports<commit_after>// mqtt
package mqtt

import (
	"encoding/json"
	"errors"
	MQTT "git.eclipse.org/gitroot/paho/org.eclipse.paho.mqtt.golang.git"
)

type Conn struct {
	opts   *MQTT.ClientOptions
	client *MQTT.Client
}

type Context struct {
	Payload []byte
	Error   error
}

type Handler func(c *Context)

func New(clientid string, conn string) *Conn {
	opts := MQTT.NewClientOptions().AddBroker(conn).SetClientID(clientid)
	return &Conn{
		opts: opts,
	}
}

func (t *Conn) Connect() error {
	t.client = MQTT.NewClient(t.opts)

	if token := t.client.Connect(); token.Wait() && token.Error() != nil {
		return token.Error()
	}
	return nil
}

func (t *Conn) Disconnect() {
	t.client.Disconnect(500)
}

func (t *Conn) On(topic string, h Handler) error {

	if token := t.client.Subscribe(topic, 0, func(client *MQTT.Client, m MQTT.Message) {
		ctx := new(Context)

		if !client.IsConnected() {
			ctx.Error = errors.New("Client not connected")
			h(ctx)
			return
		}
		client.Lock()
		ctx.Payload = m.Payload()
		h(ctx)

		client.Unlock()

	}); token.Wait() && token.Error() != nil {
		return token.Error()
	}

	return nil
}

func (t *Conn) Push(topic string, payload interface{}) error {
	buff, err := json.Marshal(payload)
	if err != nil {
		return err
	}
	token := t.client.Publish(topic, 0, false, buff)
	token.Wait()
	return token.Error()
}

func (t *Context) JSON(rcv interface{}) error {
	return json.Unmarshal(t.Payload, rcv)
}

<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"regexp"
	"strconv"
	"strings"
)

var (
	group  = regexp.MustCompile(`(?:[^/\\]|\\.)*`)
	branch = regexp.MustCompile(`(?:[^,\\]|\\.)*`)
)

func parseExpr(expr string) (tree [][]string, err error) {
	expr = strings.Replace(expr, `\,`, `\\,`, -1)
	expr = strings.Replace(expr, `\/`, `\\/`, -1)
	expr, err = strconv.Unquote(`"` + expr + `"`)
	if err != nil {
		return nil, err
	}

	gls := group.FindAllString(expr, -1)
	for gi := 0; gi < len(gls); gi++ {
		bls := branch.FindAllString(gls[gi], -1)
		for bi := 0; bi < len(bls); bi++ {
			bls[bi] = strings.Replace(bls[bi], `\,`, `,`, -1)
			bls[bi] = strings.Replace(bls[bi], `\/`, `/`, -1)
		}
		tree = append(tree, bls)
	}
	return tree, nil
}

func newMatcher(expr string, useBoundary bool) (m *regexp.Regexp, err error) {
	tree, err := parseExpr(expr)
	if err != nil {
		return nil, err
	}

	sls := make([]string, len(tree))
	for gi, bls := range tree {
		for bi := 0; bi < len(bls); bi++ {
			bls[bi] = regexp.QuoteMeta(bls[bi])
		}
		sls[gi] = "(" + strings.Join(bls, "|") + ")"
	}

	re := strings.Join(sls, "")
	if useBoundary {
		re = `\b` + re + `\b`
	}
	return regexp.Compile(re)
}

func newReplacement(exprFrom, exprTo string) ([]map[string]string, error) {
	from, err := parseExpr(exprFrom)
	if err != nil {
		return nil, err
	}
	to, err := parseExpr(exprTo)
	if err != nil {
		return nil, err
	}

	if len(from) != len(to) {
		return nil, fmt.Errorf("mismatch the number of group")
	}

	r := make([]map[string]string, len(from))
	for gi := 0; gi < len(from); gi++ {
		if len(from[gi]) != len(to[gi]) {
			return nil, fmt.Errorf("mismatch the number of branch at group[%q]", gi)
		}

		r[gi] = make(map[string]string)
		for bi := 0; bi < len(from[gi]); bi++ {
			src, dst := from[gi][bi], to[gi][bi]
			if _, exist := r[gi][src]; exist {
				return nil, fmt.Errorf("group[%q] has duplicate items", gi)
			}
			r[gi][src] = dst
		}
	}
	return r, nil
}

type Replacer struct {
	matcher     *regexp.Regexp
	replacement []map[string]string
}

func NewReplacer(from, to string, useBoundary bool) (r *Replacer, err error) {
	r = &Replacer{}

	r.matcher, err = newMatcher(from, useBoundary)
	if err != nil {
		return nil, err
	}
	r.replacement, err = newReplacement(from, to)
	if err != nil {
		return nil, err
	}

	return r, nil
}

func (r *Replacer) ReplaceAll(s string) string {
	return r.matcher.ReplaceAllStringFunc(s, func(t string) string {
		m := r.matcher.FindStringSubmatch(t)[1:]

		a := make([]string, len(m))
		for i, from := range m {
			a[i] = r.replacement[i][from]
		}
		return strings.Join(a, "")
	})
}
<commit_msg>Fix typo of '%d'<commit_after>package main

import (
	"fmt"
	"regexp"
	"strconv"
	"strings"
)

var (
	group  = regexp.MustCompile(`(?:[^/\\]|\\.)*`)
	branch = regexp.MustCompile(`(?:[^,\\]|\\.)*`)
)

func parseExpr(expr string) (tree [][]string, err error) {
	expr = strings.Replace(expr, `\,`, `\\,`, -1)
	expr = strings.Replace(expr, `\/`, `\\/`, -1)
	expr, err = strconv.Unquote(`"` + expr + `"`)
	if err != nil {
		return nil, err
	}

	gls := group.FindAllString(expr, -1)
	for gi := 0; gi < len(gls); gi++ {
		bls := branch.FindAllString(gls[gi], -1)
		for bi := 0; bi < len(bls); bi++ {
			bls[bi] = strings.Replace(bls[bi], `\,`, `,`, -1)
			bls[bi] = strings.Replace(bls[bi], `\/`, `/`, -1)
		}
		tree = append(tree, bls)
	}
	return tree, nil
}

func newMatcher(expr string, useBoundary bool) (m *regexp.Regexp, err error) {
	tree, err := parseExpr(expr)
	if err != nil {
		return nil, err
	}

	sls := make([]string, len(tree))
	for gi, bls := range tree {
		for bi := 0; bi < len(bls); bi++ {
			bls[bi] = regexp.QuoteMeta(bls[bi])
		}
		sls[gi] = "(" + strings.Join(bls, "|") + ")"
	}

	re := strings.Join(sls, "")
	if useBoundary {
		re = `\b` + re + `\b`
	}
	return regexp.Compile(re)
}

func newReplacement(exprFrom, exprTo string) ([]map[string]string, error) {
	from, err := parseExpr(exprFrom)
	if err != nil {
		return nil, err
	}
	to, err := parseExpr(exprTo)
	if err != nil {
		return nil, err
	}

	if len(from) != len(to) {
		return nil, fmt.Errorf("mismatch the number of group")
	}

	r := make([]map[string]string, len(from))
	for gi := 0; gi < len(from); gi++ {
		if len(from[gi]) != len(to[gi]) {
			return nil, fmt.Errorf("mismatch the number of branch at group[%d]", gi)
		}

		r[gi] = make(map[string]string)
		for bi := 0; bi < len(from[gi]); bi++ {
			src, dst := from[gi][bi], to[gi][bi]
			if _, exist := r[gi][src]; exist {
				return nil, fmt.Errorf("group[%d] has duplicate items", gi)
			}
			r[gi][src] = dst
		}
	}
	return r, nil
}

type Replacer struct {
	matcher     *regexp.Regexp
	replacement []map[string]string
}

func NewReplacer(from, to string, useBoundary bool) (r *Replacer, err error) {
	r = &Replacer{}

	r.matcher, err = newMatcher(from, useBoundary)
	if err != nil {
		return nil, err
	}
	r.replacement, err = newReplacement(from, to)
	if err != nil {
		return nil, err
	}

	return r, nil
}

func (r *Replacer) ReplaceAll(s string) string {
	return r.matcher.ReplaceAllStringFunc(s, func(t string) string {
		m := r.matcher.FindStringSubmatch(t)[1:]

		a := make([]string, len(m))
		for i, from := range m {
			a[i] = r.replacement[i][from]
		}
		return strings.Join(a, "")
	})
}
<|endoftext|>


<commit_before>// Copyright 2015 Zack Guo <gizak@icloud.com>. All rights reserved.
// Copyright 2015 Jesus Alvarez <jeezusjr@gmail.com>. All rights reserved.
// Use of this source code is governed by a MIT license that can
// be found in the LICENSE file.

package conui

type Grid struct {
	Rows                []Widget
	Width               int
	X                   int
	Y                   int
	BgColor             Attribute
	SelectedRow         int
	ProgressPanelHeight int
	DevicePanelHeight   int
}

func (g *Grid) selected() int {
	var x int
	var y Widget
	for x, y = range g.Rows {
		if y.IsSelected() {
			break
		}
	}
	return x
}

func (g *Grid) deselectAll() {
	for x, _ := range g.Rows {
		if _, ok := g.Rows[x].(*DevicePanel); !ok {
			continue
		}
		g.Rows[x].SetSelected(false)
		g.Rows[x].(*DevicePanel).Border.FgColor = ColorWhite
	}
}

func (g *Grid) NumVisible() int {
	num := 0
	for x := 1; x < len(g.Rows)-1; x++ {
		if g.Rows[x].(*DevicePanel).IsVisible() {
			num += 1
		}
	}
	return num
}

func (g *Grid) Select(index int) *DevicePanel {
	g.deselectAll()
	wg := g.Rows[index].(*DevicePanel)
	g.SelectedRow = index
	wg.SetSelected(true)
	wg.SetVisible(true)
	return wg
}

func (g *Grid) scrollVisible() {
	visibleArea := TermHeight() - 5

	Log.Debugf("scrollVisible: visibleArea: %d g.SelectedRow: %d numVisibleWidgets: %d",
		visibleArea, g.SelectedRow, g.NumVisible())

	if (TermHeight() - g.ProgressPanelHeight) < g.DevicePanelHeight {
		Log.Debugln("scrollVisible: Rendering only selected panel (not enough term height)")
		for x := 1; x < len(g.Rows)-1; x++ {
			if dp := g.DevicePanelByIndex(x); dp != nil {
				if x == g.SelectedRow {
					dp.SetY(g.ProgressPanelHeight)
					continue
				}
			}
		}
	} else if g.SelectedRow == 1 {
		Log.Debugln("scrollVisible: First visible panel selected")
		yPos := 5
		for x := 1; x < len(g.Rows)-1; x++ {
			if dp := g.DevicePanelByIndex(x); dp != nil {
				if !dp.IsVisible() {
					continue
				}
				dp.SetY(yPos)
				yPos += g.DevicePanelHeight
			}
		}
	} else if g.DevicePanelByIndexNextVisible(g.SelectedRow) == g.SelectedRow {
		Log.Debugln("scrollVisible: Last visible panel selected")
		yPos := TermHeight() - g.DevicePanelHeight
		for x := len(g.Rows) - 1; x > 0; x-- {
			if dp := g.DevicePanelByIndex(x); dp != nil {
				if !dp.IsVisible() {
					continue
				}
				dp.SetY(yPos)
				yPos -= g.DevicePanelHeight
			}
		}
	} else {
		Log.Debugln("scrollVisible: In-between panel selected")
		yPos := ((visibleArea / 2) - (g.DevicePanelHeight / 2)) + g.ProgressPanelHeight
		for x := 1; x < len(g.Rows)-1; x++ {
			dp := g.DevicePanelByIndex(x)
			if x == g.SelectedRow-1 {
				dp.SetY(yPos - g.DevicePanelHeight)
				continue
			}
			dp.SetY(yPos)
			yPos += g.DevicePanelHeight
		}
	}
}

func (g *Grid) SelectPrevious() *DevicePanel {
	g.SelectedRow = g.selected()
	g.deselectAll()
	var wg *DevicePanel
	var ok bool
	for {
		g.SelectedRow--
		if g.SelectedRow < 0 {
			g.SelectedRow = len(g.Rows) - 1
		}
		if wg, ok = g.Rows[g.SelectedRow].(*DevicePanel); ok {
			visible := wg.IsVisible()
			Log.Debugf("SELECTED previous Widget[%d].Visible = %t", g.SelectedRow, visible)
			if visible {
				Log.Debugf("SelectPrevious: termHeight: %d wg.Y: %d wg.Height: %d", TermHeight(), wg.Y(), wg.Height())
				if (g.NumVisible() * g.Rows[1].Height()) > (TermHeight() - 5) {
					g.scrollVisible()
				}
				break
			}
		}
	}
	wg.SetSelected(true)
	return wg
}

func (g *Grid) SelectNext() *DevicePanel {
	g.SelectedRow = g.selected()
	g.deselectAll()
	var wg *DevicePanel
	var ok bool
	for {
		g.SelectedRow++
		if g.SelectedRow > len(g.Rows)-1 {
			g.SelectedRow = 0
		}
		if wg, ok = g.Rows[g.SelectedRow].(*DevicePanel); ok {
			visible := wg.IsVisible()
			Log.Debugf("SelectNext: Widget[%d].Visible = %t", g.SelectedRow, visible)
			if visible {
				Log.Debugf("SelectNext: termHeight: %d wg.Y: %d wg.Height: %d", TermHeight(), wg.Y(), wg.Height())
				if (g.NumVisible() * g.Rows[1].Height()) > (TermHeight() - 5) {
					g.scrollVisible()
				}
				break
			}
		}
	}
	wg.SetSelected(true)
	return wg
}

func (g *Grid) Selected() *DevicePanel {
	return g.Rows[g.SelectedRow].(*DevicePanel)
}

func (g *Grid) DevicePanelByIndex(index int) *DevicePanel {
	if wg, ok := g.Rows[index].(*DevicePanel); ok {
		return wg
	}
	return nil
}

func (g *Grid) DevicePanelByIndexPreviousVisible(index int) int {
	if index == 0 {
		return 1
	}
	for x := index; x > 1; x-- {
		if g.Rows[x].(*DevicePanel).IsVisible() {
			return x
		}
	}
	return index
}

func (g *Grid) DevicePanelByIndexNextVisible(index int) int {
	if index+1 > len(g.Rows) {
		return index
	}
	for x := index + 1; x < len(g.Rows)-1; x++ {
		if g.Rows[x].(*DevicePanel).IsVisible() {
			return x
		}
	}
	return index
}

func (g *Grid) PromptByIndex(index int, prompt PromptAction) *DevicePanel {
	wg := g.Rows[index].(*DevicePanel)
	if wg != nil {
		g.Select(index)
		wg.SetVisible(true)
	}
	return wg
}

// ProgressGauge returns the overall progress gauge from the widget list.
func (g *Grid) ProgressGauge() *ProgressGauge {
	return g.Rows[len(g.Rows)-1].(*ProgressGauge)
}

// NewGrid returns *Grid with given rows.
func NewGrid(rows ...Widget) *Grid {
	return &Grid{Rows: rows}
}

// AddRows appends given rows to Grid.
func (g *Grid) AddRows(rs ...Widget) {
	for _, y := range rs {
		g.Rows = append(g.Rows, y)
	}
}

// Buffer implments Bufferer interface.
func (g Grid) Buffer() []Point {
	ps := []Point{}
	// LIFO with the rows... row 0 has the highest priority, meaning the codes in row 0 cannot be overwritten.
	for x := len(g.Rows) - 1; x >= 0; x-- {
		ps = append(ps, g.Rows[x].Buffer()...)
	}
	return ps
}
<commit_msg>Fix scrolling for more than 3 active devices<commit_after>// Copyright 2015 Zack Guo <gizak@icloud.com>. All rights reserved.
// Copyright 2015 Jesus Alvarez <jeezusjr@gmail.com>. All rights reserved.
// Use of this source code is governed by a MIT license that can
// be found in the LICENSE file.

package conui

type Grid struct {
	Rows                []Widget
	Width               int
	X                   int
	Y                   int
	BgColor             Attribute
	SelectedRow         int
	ProgressPanelHeight int
	DevicePanelHeight   int
}

func (g *Grid) selected() int {
	var x int
	var y Widget
	for x, y = range g.Rows {
		if y.IsSelected() {
			break
		}
	}
	return x
}

func (g *Grid) deselectAll() {
	for x, _ := range g.Rows {
		if _, ok := g.Rows[x].(*DevicePanel); !ok {
			continue
		}
		g.Rows[x].SetSelected(false)
		g.Rows[x].(*DevicePanel).Border.FgColor = ColorWhite
	}
}

func (g *Grid) NumVisible() int {
	num := 0
	for x := 1; x < len(g.Rows)-1; x++ {
		if g.Rows[x].(*DevicePanel).IsVisible() {
			num += 1
		}
	}
	return num
}

func (g *Grid) Select(index int) *DevicePanel {
	g.deselectAll()
	wg := g.Rows[index].(*DevicePanel)
	g.SelectedRow = index
	wg.SetSelected(true)
	wg.SetVisible(true)
	return wg
}

func (g *Grid) scrollVisible() {
	visibleArea := TermHeight() - 5

	Log.Debugf("scrollVisible: visibleArea: %d g.SelectedRow: %d numVisibleWidgets: %d",
		visibleArea, g.SelectedRow, g.NumVisible())

	if (TermHeight() - g.ProgressPanelHeight) < g.DevicePanelHeight {
		Log.Debugln("scrollVisible: Rendering only selected panel (not enough term height)")
		for x := 1; x < len(g.Rows)-1; x++ {
			if dp := g.DevicePanelByIndex(x); dp != nil {
				if x == g.SelectedRow {
					dp.SetY(g.ProgressPanelHeight)
					continue
				}
			}
		}
	} else if g.SelectedRow == 1 {
		Log.Debugln("scrollVisible: First visible panel selected")
		yPos := 5
		for x := 1; x < len(g.Rows)-1; x++ {
			if dp := g.DevicePanelByIndex(x); dp != nil {
				if !dp.IsVisible() {
					continue
				}
				dp.SetY(yPos)
				yPos += g.DevicePanelHeight
			}
		}
	} else if g.DevicePanelByIndexNextVisible(g.SelectedRow) == g.SelectedRow {
		Log.Debugln("scrollVisible: Last visible panel selected")
		yPos := TermHeight() - g.DevicePanelHeight
		for x := len(g.Rows) - 1; x > 0; x-- {
			if dp := g.DevicePanelByIndex(x); dp != nil {
				if !dp.IsVisible() {
					continue
				}
				dp.SetY(yPos)
				yPos -= g.DevicePanelHeight
			}
		}
	} else {
		Log.Debugln("scrollVisible: In-between panel selected")
		if dp := g.DevicePanelByIndex(g.SelectedRow); dp != nil {
			if (dp.Y()+g.DevicePanelHeight) < TermHeight() && dp.Y() > g.ProgressPanelHeight {
				Log.Debugln("scrollVisible: SelectedRow is fully visible, not doing anything")
				return
			}
		}
		var visiblePanels []int
		// The selected device will be set to the middle of the visible area
		var selRowInVis int
		for x := 1; x < len(g.Rows)-1; x++ {
			if dp := g.DevicePanelByIndex(x); dp != nil {
				if dp.IsVisible() {
					visiblePanels = append(visiblePanels, x)
					if x == g.SelectedRow {
						selRowInVis = len(visiblePanels) - 1
					}
				}
			}
		}
		Log.Debugf("scrollVisible: visiblePanels: %+v g.SelectedRow: %d", visiblePanels, g.SelectedRow)
		yPos := ((visibleArea / 2) - (g.DevicePanelHeight / 2)) + g.ProgressPanelHeight
		for x := 0; x < len(visiblePanels); x++ {
			if dp := g.DevicePanelByIndex(visiblePanels[x]); dp != nil {
				if x < selRowInVis {
					Log.Debugln("scrollVisible:", selRowInVis-x, "rows before from g.SelectedRow")
					ny := yPos - ((selRowInVis - x) * g.DevicePanelHeight)
					Log.Debugf("scrollVisible: visiblePanels[%d] = %d", x, visiblePanels[x])
					Log.Debugf("scrollVisible: g.Rows[%d].Y = %d", visiblePanels[x], ny)
					dp.SetY(ny)
					continue
				} else if x == selRowInVis {
					Log.Debugf("scrollVisible: g.Rows[%d].Y = %d", g.SelectedRow, yPos)
					dp.SetY(yPos)
				} else {
					Log.Debugln("scrollVisible:", x+1, "rows after g.SelectedRow")
					dp.SetY(yPos)
				}
				yPos += g.DevicePanelHeight
			}
		}
	}
}

func (g *Grid) SelectPrevious() *DevicePanel {
	g.SelectedRow = g.selected()
	g.deselectAll()
	var wg *DevicePanel
	var ok bool
	for {
		g.SelectedRow--
		if g.SelectedRow < 0 {
			g.SelectedRow = len(g.Rows) - 1
		}
		if wg, ok = g.Rows[g.SelectedRow].(*DevicePanel); ok {
			visible := wg.IsVisible()
			Log.Debugf("SELECTED previous Widget[%d].Visible = %t", g.SelectedRow, visible)
			if visible {
				Log.Debugf("SelectPrevious: termHeight: %d wg.Y: %d wg.Height: %d", TermHeight(), wg.Y(), wg.Height())
				if (g.NumVisible() * g.Rows[1].Height()) > (TermHeight() - 5) {
					g.scrollVisible()
				}
				break
			}
		}
	}
	wg.SetSelected(true)
	return wg
}

func (g *Grid) SelectNext() *DevicePanel {
	g.SelectedRow = g.selected()
	g.deselectAll()
	var wg *DevicePanel
	var ok bool
	for {
		g.SelectedRow++
		if g.SelectedRow > len(g.Rows)-1 {
			g.SelectedRow = 0
		}
		if wg, ok = g.Rows[g.SelectedRow].(*DevicePanel); ok {
			visible := wg.IsVisible()
			Log.Debugf("SelectNext: Widget[%d].Visible = %t", g.SelectedRow, visible)
			if visible {
				Log.Debugf("SelectNext: termHeight: %d wg.Y: %d wg.Height: %d", TermHeight(), wg.Y(), wg.Height())
				if (g.NumVisible() * g.Rows[1].Height()) > (TermHeight() - 5) {
					g.scrollVisible()
				}
				break
			}
		}
	}
	wg.SetSelected(true)
	return wg
}

func (g *Grid) Selected() *DevicePanel {
	return g.Rows[g.SelectedRow].(*DevicePanel)
}

func (g *Grid) DevicePanelByIndex(index int) *DevicePanel {
	if wg, ok := g.Rows[index].(*DevicePanel); ok {
		return wg
	}
	return nil
}

func (g *Grid) DevicePanelByIndexPreviousVisible(index int) int {
	if index == 0 {
		return 1
	}
	for x := index; x > 1; x-- {
		if g.Rows[x].(*DevicePanel).IsVisible() {
			return x
		}
	}
	return index
}

func (g *Grid) DevicePanelByIndexNextVisible(index int) int {
	if index+1 > len(g.Rows) {
		return index
	}
	for x := index + 1; x < len(g.Rows)-1; x++ {
		if g.Rows[x].(*DevicePanel).IsVisible() {
			return x
		}
	}
	return index
}

func (g *Grid) PromptByIndex(index int, prompt PromptAction) *DevicePanel {
	wg := g.Rows[index].(*DevicePanel)
	if wg != nil {
		g.Select(index)
		wg.SetVisible(true)
	}
	return wg
}

// ProgressGauge returns the overall progress gauge from the widget list.
func (g *Grid) ProgressGauge() *ProgressGauge {
	return g.Rows[len(g.Rows)-1].(*ProgressGauge)
}

// NewGrid returns *Grid with given rows.
func NewGrid(rows ...Widget) *Grid {
	return &Grid{Rows: rows}
}

// AddRows appends given rows to Grid.
func (g *Grid) AddRows(rs ...Widget) {
	for _, y := range rs {
		g.Rows = append(g.Rows, y)
	}
}

// Buffer implments Bufferer interface.
func (g Grid) Buffer() []Point {
	ps := []Point{}
	// LIFO with the rows... row 0 has the highest priority, meaning the codes in row 0 cannot be overwritten.
	for x := len(g.Rows) - 1; x >= 0; x-- {
		ps = append(ps, g.Rows[x].Buffer()...)
	}
	return ps
}
<|endoftext|>


<commit_before>package logging

import (
	"fmt"
	"io"
	"net/http"
	"strings"
	"time"
)

const ApacheFormatPattern = "%s - - [%s] \"%s %d %d\" %f\n"

type ApacheLogRecord struct {
	http.ResponseWriter

	ip                    string
	time                  time.Time
	method, uri, protocol string
	status                int
	responseBytes         int64
	elapsedTime           time.Duration
}

func (r *ApacheLogRecord) Log(out io.Writer) {
	timeFormatted := r.time.Format("02/Jan/2006 03:04:05")
	requestLine := fmt.Sprintf("%s %s %s", r.method, r.uri, r.protocol)
	fmt.Fprintf(out, ApacheFormatPattern, r.ip, timeFormatted, requestLine, r.status, r.responseBytes,
		r.elapsedTime.Seconds())
}

func (r *ApacheLogRecord) Write(p []byte) (int, error) {
	written, err := r.ResponseWriter.Write(p)
	r.responseBytes += int64(written)
	return written, err
}

func (r *ApacheLogRecord) WriteHeader(status int) {
	r.status = status
	r.ResponseWriter.WriteHeader(status)
}

type ApacheLoggingHandler struct {
	handler http.Handler
	out     io.Writer
}

func NewApacheLoggingHandler(handler http.Handler, out io.Writer) http.Handler {
	return &ApacheLoggingHandler{
		handler: handler,
		out:     out,
	}
}

func (h *ApacheLoggingHandler) ServeHTTP(rw http.ResponseWriter, r *http.Request) {
	clientIP := r.RemoteAddr
	if colon := strings.LastIndex(clientIP, ":"); colon != -1 {
		clientIP = clientIP[:colon]
	}

	record := &ApacheLogRecord{
		ResponseWriter: rw,
		ip:             clientIP,
		time:           time.Time{},
		method:         r.Method,
		uri:            r.RequestURI,
		protocol:       r.Proto,
		status:         http.StatusOK,
		elapsedTime:    time.Duration(0),
	}

	startTime := time.Now()
	h.handler.ServeHTTP(record, r)
	finishTime := time.Now()

	record.time = finishTime.UTC()
	record.elapsedTime = finishTime.Sub(startTime)

	record.Log(h.out)
}
<commit_msg>Make sure to log panicd requests as well<commit_after>package logging

import (
	"fmt"
	"io"
	"net/http"
	"runtime/debug"
	"strings"
	"time"

	"github.com/pkg/errors"
)

const ApacheFormatPattern = "%s - - [%s] \"%s %d %d\" %f\n"

type ApacheLogRecord struct {
	http.ResponseWriter

	ip                    string
	time                  time.Time
	method, uri, protocol string
	status                int
	responseBytes         int64
	elapsedTime           time.Duration
}

func (r *ApacheLogRecord) Log(out io.Writer) {
	timeFormatted := r.time.Format("02/Jan/2006 03:04:05")
	requestLine := fmt.Sprintf("%s %s %s", r.method, r.uri, r.protocol)
	fmt.Fprintf(out, ApacheFormatPattern, r.ip, timeFormatted, requestLine, r.status, r.responseBytes,
		r.elapsedTime.Seconds())
}

func (r *ApacheLogRecord) Write(p []byte) (int, error) {
	written, err := r.ResponseWriter.Write(p)
	r.responseBytes += int64(written)
	return written, err
}

func (r *ApacheLogRecord) WriteHeader(status int) {
	r.status = status
	r.ResponseWriter.WriteHeader(status)
}

type ApacheLoggingHandler struct {
	handler http.Handler
	out     io.Writer
}

func NewApacheLoggingHandler(handler http.Handler, out io.Writer) http.Handler {
	return &ApacheLoggingHandler{
		handler: handler,
		out:     out,
	}
}

func (h *ApacheLoggingHandler) runHandler(rw http.ResponseWriter, r *http.Request) (err error) {
	defer func() {
		if rec := recover(); rec != nil {
			var ok bool
			err, ok = rec.(error)
			if !ok {
				err = errors.Wrap(fmt.Errorf(string(debug.Stack())), "Error running handler")
			}
		}
	}()
	h.handler.ServeHTTP(rw, r)
	return
}

func (h *ApacheLoggingHandler) ServeHTTP(rw http.ResponseWriter, r *http.Request) {
	clientIP := r.RemoteAddr
	if colon := strings.LastIndex(clientIP, ":"); colon != -1 {
		clientIP = clientIP[:colon]
	}

	record := &ApacheLogRecord{
		ResponseWriter: rw,
		ip:             clientIP,
		time:           time.Time{},
		method:         r.Method,
		uri:            r.RequestURI,
		protocol:       r.Proto,
		status:         http.StatusOK,
		elapsedTime:    time.Duration(0),
	}

	startTime := time.Now()
	if err := h.runHandler(record, r); err != nil {
		http.Error(record, err.Error(), http.StatusInternalServerError)
	}
	finishTime := time.Now()

	record.time = finishTime.UTC()
	record.elapsedTime = finishTime.Sub(startTime)

	record.Log(h.out)
}
<|endoftext|>


<commit_before>// +build !appengine

package logutil

import (
	"bytes"
	"fmt"
	"io"
	"runtime"
	"unicode/utf8"
)

const (
	apiErrorStringBase  = "Code: %d, Detail: %s, Service: %s"
	callErrorStringBase = "Code: %d, Detail: %s, Timeout: %t"
	unknownErrorString  = "Unknown Error"
)

func sprintf(format string, args ...interface{}) string {
	_, file, line, _ := runtime.Caller(2)
	var fileLine = fmt.Sprintf("%s:%d]", file, line)
	return fmt.Sprintf("%s %s", fileLine, fmt.Sprintf(format, args...))
}

func Debugf(c appengine.Context, format string, args ...interface{}) {
	c.Debugf(sprintf(format, args...))
}

func Infof(c appengine.Context, format string, args ...interface{}) {
	c.Infof(sprintf(format, args...))
}

func Warningf(c appengine.Context, format string, args ...interface{}) {
	c.Warningf(sprintf(format, args...))
}

func Errorf(c appengine.Context, format string, args ...interface{}) {
	c.Errorf(sprintf(format, args...))
}

func Criticalf(c appengine.Context, format string, args ...interface{}) {
	c.Criticalf(sprintf(format, args...))
}

func ErrorStackTracef(c appengine.Context, format string, args ...interface{}) {
	c.Errorf(sprintf("%s", StackTrace(2, 2048)))
	c.Errorf(sprintf(format, args...))
}

//https://github.com/knightso/base/blob/master/errors/errors.go
func StackTrace(skip, maxBytes int) []byte {
	// this func is debug purpose and ignores errors

	buf := make([]byte, maxBytes)
	n := runtime.Stack(buf, false)
	var gotall bool
	if n < len(buf) {
		buf = buf[:n]
		gotall = true
	} else {
		for !utf8.Valid(buf) || len(buf) == 0 {
			buf = buf[:len(buf)-1]
		}
	}

	var w bytes.Buffer

	writeOrSkip := func(buf []byte, w io.Writer, line int) {
		if line == 1 || line > 1+skip*2 {
			w.Write(buf)
		}
	}

	line := 1
	for { //EOFまでloopする
		lf := bytes.IndexByte(buf, '\n')
		if lf < 0 {
			writeOrSkip(buf, &w, line)
			break
		}
		writeOrSkip(buf[:lf+1], &w, line)
		buf = buf[lf+1:]
		line++
	}

	if !gotall {
		w.WriteString("\n        ... (omitted)")
	}
	w.WriteString("\n")

	return w.Bytes()
}
<commit_msg>remove unused<commit_after>// +build !appengine

package logutil

import (
	"bytes"
	"fmt"
	"io"
	"runtime"
	"unicode/utf8"
)

const ()

func sprintf(format string, args ...interface{}) string {
	_, file, line, _ := runtime.Caller(2)
	var fileLine = fmt.Sprintf("%s:%d]", file, line)
	return fmt.Sprintf("%s %s", fileLine, fmt.Sprintf(format, args...))
}

func Debugf(c appengine.Context, format string, args ...interface{}) {
	c.Debugf(sprintf(format, args...))
}

func Infof(c appengine.Context, format string, args ...interface{}) {
	c.Infof(sprintf(format, args...))
}

func Warningf(c appengine.Context, format string, args ...interface{}) {
	c.Warningf(sprintf(format, args...))
}

func Errorf(c appengine.Context, format string, args ...interface{}) {
	c.Errorf(sprintf(format, args...))
}

func Criticalf(c appengine.Context, format string, args ...interface{}) {
	c.Criticalf(sprintf(format, args...))
}

func ErrorStackTracef(c appengine.Context, format string, args ...interface{}) {
	c.Errorf(sprintf("%s", StackTrace(2, 2048)))
	c.Errorf(sprintf(format, args...))
}

//https://github.com/knightso/base/blob/master/errors/errors.go
func StackTrace(skip, maxBytes int) []byte {
	// this func is debug purpose and ignores errors

	buf := make([]byte, maxBytes)
	n := runtime.Stack(buf, false)
	var gotall bool
	if n < len(buf) {
		buf = buf[:n]
		gotall = true
	} else {
		for !utf8.Valid(buf) || len(buf) == 0 {
			buf = buf[:len(buf)-1]
		}
	}

	var w bytes.Buffer

	writeOrSkip := func(buf []byte, w io.Writer, line int) {
		if line == 1 || line > 1+skip*2 {
			w.Write(buf)
		}
	}

	line := 1
	for { //EOFまでloopする
		lf := bytes.IndexByte(buf, '\n')
		if lf < 0 {
			writeOrSkip(buf, &w, line)
			break
		}
		writeOrSkip(buf[:lf+1], &w, line)
		buf = buf[lf+1:]
		line++
	}

	if !gotall {
		w.WriteString("\n        ... (omitted)")
	}
	w.WriteString("\n")

	return w.Bytes()
}
<|endoftext|>


<commit_before>package qlog

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

	"github.com/spf13/pflag"

	"github.com/fsnotify/fsnotify"
	"github.com/sirupsen/logrus"
	"github.com/spf13/viper"
)

// Logger is an alias of logrus.Logger
type Logger = logrus.Logger

// Fields is an alias of logrus.Fields
type Fields = logrus.Fields

// type Logger struct {
// 	*logrus.Logger
// }

type loggerConfig struct {
	Path []string
	Name string
	Typ  string
	File string
}

var (
	// flagset
	cli = pflag.NewFlagSet(os.Args[0], pflag.ExitOnError)

	// viper
	v = viper.New()

	// DefaultLogger : default logger object
	qLogger = logrus.StandardLogger()

	qLoggerConfig = &loggerConfig{
		Path: make([]string, 0),
	}
)

const (
	keyConfigPath = "logger.config.path"
	keyConfigName = "logger.config.name"
	keyConfigType = "logger.config.type"
	keyConfigFile = "logger.config.file"

	keyReportCaller         = "logger.reportcaller"
	keyDefaultLevel         = "logger.level"
	keyDefaultFormatterName = "logger.formatter.name"
	keyDefaultFormatterOpts = "logger.formatter.opts"
)

func setDefault() {
	v.SetDefault(keyReportCaller, false)
	v.SetDefault(keyDefaultLevel, "debug")
	v.SetDefault(keyDefaultFormatterName, "text")
}

func initFlags() error {
	cli.Bool(keyReportCaller, false, "logger.reportcaller")
	cli.String(keyDefaultLevel, "error", "logger.level")
	cli.String(keyDefaultFormatterName, "text", "logger.formatter.name")

	cli.StringSliceVar(&qLoggerConfig.Path, keyConfigPath, []string{".", "./conf", "/etc/qlog"}, "logger.config.path")
	cli.StringVar(&qLoggerConfig.Name, keyConfigName, "logger", "logger.config.name")
	cli.StringVar(&qLoggerConfig.Typ, keyConfigType, "yaml", "logger.config.type")

	cli.StringVar(&qLoggerConfig.File, keyConfigFile, "", "logger.config.file")

	return nil
}

func initViper() error {
	// read from flags
	cli.Parse(filterLoggerFlags(os.Args[1:], true))
	v.BindPFlags(cli)

	// read from env
	v.AutomaticEnv()
	v.SetEnvKeyReplacer(strings.NewReplacer(".", "_"))

	// set default
	setDefault()

	// read from config file
	if len(qLoggerConfig.File) > 0 {
		v.SetConfigFile(qLoggerConfig.File)
	} else {
		for _, p := range qLoggerConfig.Path {
			v.AddConfigPath(p)
		}
		v.SetConfigName(qLoggerConfig.Name)
	}
	v.SetConfigType(qLoggerConfig.Typ)

	if err := v.ReadInConfig(); err != nil {
		// no config file
		// return err
	} else {
		// watch configs changes
		v.WatchConfig()
		v.OnConfigChange(func(e fsnotify.Event) {
			fmt.Println("[qlog] config changed: ", e.Name)
			resetLogger()
		})
	}

	//v.Debug()

	return nil
}

func resetLogger() {
	if err := configLogger(); err != nil {
		fmt.Printf("[qlog] reload config fail:%s, changes may not take effect!", err)
	}
}

func getDefaultFormatter() (logrus.Formatter, error) {
	return newFormatter(v.GetString(keyDefaultFormatterName), keyDefaultFormatterOpts)
}

func getActivateHooks() (logrus.LevelHooks, error) {
	var err error
	var hook logrus.Hook
	var activateHooks = make(logrus.LevelHooks)

	for name := range gRegisteredHooks {
		n := strings.Join([]string{"logger", name, "enabled"}, ".")
		//fmt.Println("initHooks", n, v.GetBool(n))
		if v.GetBool(n) == true {
			if hook, err = newHook(name); err != nil {
				fmt.Printf("[qlog] init hook(%s) error:%s\n", name, err)
				continue
			}
			activateHooks.Add(hook)
		}
	}

	if len(activateHooks) == 0 {
		return nil, errors.New("no activate log hook")
	}

	return activateHooks, nil
}

func configLogger() error {
	var err error

	qLogger.SetReportCaller(v.GetBool(keyReportCaller))

	level, err := logrus.ParseLevel(v.GetString(keyDefaultLevel))

	if err != nil {
		return fmt.Errorf("get default log level error: %s", err)
	}
	qLogger.SetLevel(level)

	formatter, err := getDefaultFormatter()
	if err != nil {
		return fmt.Errorf("get default formatters error: %s", err)
	}
	qLogger.SetFormatter(formatter)

	// SetLevel and SetFormatter must be called before getActivateHooks.
	hooks, err := getActivateHooks()

	if err != nil {
		fmt.Printf("[qlog] get hooks error: %s\n", err)
		qLogger.ReplaceHooks(nil)
		qLogger.SetOutput(os.Stderr)
		return nil
	}

	qLogger.SetOutput(ioutil.Discard)
	qLogger.ReplaceHooks(hooks)
	return nil
}

func init() {
	var err error

	if err = initSysParams(); err != nil {
		panic(fmt.Sprint("[qlog] init system param error:", err))
	}

	if err = initFlags(); err != nil {
		panic(fmt.Sprint("[qlog] init flags error:", err))
	}

	if err = initViper(); err != nil {
		panic(fmt.Sprint("[qlog] init viper error:", err))
	}

	if err = configLogger(); err != nil {
		panic(fmt.Sprint("[qlog] configLogger fail:", err))
	}
}
<commit_msg>use exported standardlogger<commit_after>package qlog

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

	"github.com/spf13/pflag"

	"github.com/fsnotify/fsnotify"
	"github.com/sirupsen/logrus"
	"github.com/spf13/viper"
)

// Logger is an alias of logrus.Logger
type Logger = logrus.Logger

// Fields is an alias of logrus.Fields
type Fields = logrus.Fields

// type Logger struct {
// 	*logrus.Logger
// }

type loggerConfig struct {
	Path []string
	Name string
	Typ  string
	File string
}

var (
	// flagset
	cli = pflag.NewFlagSet(os.Args[0], pflag.ExitOnError)

	// viper
	v = viper.New()

	// DefaultLogger : default logger object
	qLogger = StandardLogger()

	qLoggerConfig = &loggerConfig{
		Path: make([]string, 0),
	}
)

const (
	keyConfigPath = "logger.config.path"
	keyConfigName = "logger.config.name"
	keyConfigType = "logger.config.type"
	keyConfigFile = "logger.config.file"

	keyReportCaller         = "logger.reportcaller"
	keyDefaultLevel         = "logger.level"
	keyDefaultFormatterName = "logger.formatter.name"
	keyDefaultFormatterOpts = "logger.formatter.opts"
)

func setDefault() {
	v.SetDefault(keyReportCaller, false)
	v.SetDefault(keyDefaultLevel, "debug")
	v.SetDefault(keyDefaultFormatterName, "text")
}

func initFlags() error {
	cli.Bool(keyReportCaller, false, "logger.reportcaller")
	cli.String(keyDefaultLevel, "error", "logger.level")
	cli.String(keyDefaultFormatterName, "text", "logger.formatter.name")

	cli.StringSliceVar(&qLoggerConfig.Path, keyConfigPath, []string{".", "./conf", "/etc/qlog"}, "logger.config.path")
	cli.StringVar(&qLoggerConfig.Name, keyConfigName, "logger", "logger.config.name")
	cli.StringVar(&qLoggerConfig.Typ, keyConfigType, "yaml", "logger.config.type")

	cli.StringVar(&qLoggerConfig.File, keyConfigFile, "", "logger.config.file")

	return nil
}

func initViper() error {
	// read from flags
	cli.Parse(filterLoggerFlags(os.Args[1:], true))
	v.BindPFlags(cli)

	// read from env
	v.AutomaticEnv()
	v.SetEnvKeyReplacer(strings.NewReplacer(".", "_"))

	// set default
	setDefault()

	// read from config file
	if len(qLoggerConfig.File) > 0 {
		v.SetConfigFile(qLoggerConfig.File)
	} else {
		for _, p := range qLoggerConfig.Path {
			v.AddConfigPath(p)
		}
		v.SetConfigName(qLoggerConfig.Name)
	}
	v.SetConfigType(qLoggerConfig.Typ)

	if err := v.ReadInConfig(); err != nil {
		// no config file
		// return err
	} else {
		// watch configs changes
		v.WatchConfig()
		v.OnConfigChange(func(e fsnotify.Event) {
			fmt.Println("[qlog] config changed: ", e.Name)
			resetLogger()
		})
	}

	//v.Debug()

	return nil
}

func resetLogger() {
	if err := configLogger(); err != nil {
		fmt.Printf("[qlog] reload config fail:%s, changes may not take effect!", err)
	}
}

func getDefaultFormatter() (logrus.Formatter, error) {
	return newFormatter(v.GetString(keyDefaultFormatterName), keyDefaultFormatterOpts)
}

func getActivateHooks() (logrus.LevelHooks, error) {
	var err error
	var hook logrus.Hook
	var activateHooks = make(logrus.LevelHooks)

	for name := range gRegisteredHooks {
		n := strings.Join([]string{"logger", name, "enabled"}, ".")
		//fmt.Println("initHooks", n, v.GetBool(n))
		if v.GetBool(n) == true {
			if hook, err = newHook(name); err != nil {
				fmt.Printf("[qlog] init hook(%s) error:%s\n", name, err)
				continue
			}
			activateHooks.Add(hook)
		}
	}

	if len(activateHooks) == 0 {
		return nil, errors.New("no activate log hook")
	}

	return activateHooks, nil
}

func configLogger() error {
	var err error

	qLogger.SetReportCaller(v.GetBool(keyReportCaller))

	level, err := logrus.ParseLevel(v.GetString(keyDefaultLevel))

	if err != nil {
		return fmt.Errorf("get default log level error: %s", err)
	}
	qLogger.SetLevel(level)

	formatter, err := getDefaultFormatter()
	if err != nil {
		return fmt.Errorf("get default formatters error: %s", err)
	}
	qLogger.SetFormatter(formatter)

	// SetLevel and SetFormatter must be called before getActivateHooks.
	hooks, err := getActivateHooks()

	if err != nil {
		fmt.Printf("[qlog] get hooks error: %s\n", err)
		qLogger.ReplaceHooks(nil)
		qLogger.SetOutput(os.Stderr)
		return nil
	}

	qLogger.SetOutput(ioutil.Discard)
	qLogger.ReplaceHooks(hooks)
	return nil
}

func init() {
	var err error

	if err = initSysParams(); err != nil {
		panic(fmt.Sprint("[qlog] init system param error:", err))
	}

	if err = initFlags(); err != nil {
		panic(fmt.Sprint("[qlog] init flags error:", err))
	}

	if err = initViper(); err != nil {
		panic(fmt.Sprint("[qlog] init viper error:", err))
	}

	if err = configLogger(); err != nil {
		panic(fmt.Sprint("[qlog] configLogger fail:", err))
	}
}
<|endoftext|>


<commit_before>package logger

import (
	"io"
	"os"

	"context"

	"sync"

	"cloud.google.com/go/errorreporting"
	"github.com/mgutz/logxi/v1"
	"github.com/pkg/errors"
)

// UnaLogger wraps a logxi logger
// and delegate to some of it's logging methods
type UnaLogger interface {
	Debug(msg string, args ...interface{})
	Info(msg string, args ...interface{})
	Error(msg string, err error, args ...interface{})
	Fatal(msg string, err error, args ...interface{})
	Underlying() log.Logger
}

type unaLogger struct {
	Logger log.Logger
	name   string
}

// Config contains Name and FileName for the logger
type Config struct {
	Name     string
	FileName string
}

// Keep a list of loggers that we can use in the SetLevel func
var loggers []UnaLogger

var errorClient *errorreporting.Client

// logger for internal use
var lgr UnaLogger

// ExitOnPanic makes it possible to disable exiting in ReportPanics
var ExitOnPanic = true

// InitErrorReporting will enable the errors of all calls to Error and Fatal to be sent to Google Error Reporting
// It also enables the
func InitErrorReporting(ctx context.Context, projectID, serviceName, serviceVersion string) error {
	lgr = New("unalogger")
	client, err := errorreporting.NewClient(ctx, projectID,
		errorreporting.Config{
			ServiceName:    serviceName,
			ServiceVersion: serviceVersion})
	if err != nil {
		return err
	}

	errorClient = client

	return nil
}

// ReportPanics should be defered in every new scope where you want to catch pancis and have them pass on to Stackdriver
// Error Reporting
func ReportPanics(ctx context.Context) func() {
	return func() {
		if errorClient == nil {
			panic("The errorClient was nil, initialize it with InitErrorReporting before deferring this function")
		}
		x := recover()
		if x == nil {
			return
		}
		switch e := x.(type) {
		case string:
			err := errorClient.ReportSync(ctx, errorreporting.Entry{Error: errors.New(e)})
			if err != nil {
				lgr.Error("Couldn't do a ReportSync to Stackdriver Error Reporting", err)
			}
		case error:
			err := errorClient.ReportSync(ctx, errorreporting.Entry{Error: e})
			if err != nil {
				lgr.Error("Couldn't do a ReportSync to Stackdriver Error Reporting", err)
			}
		default:
			panic(x)
		}
		// exits with a non-zero code so the app execution stops
		if ExitOnPanic {
			os.Exit(1337)
		}
	}
}

// CloseClient should be deferred right after calling InitErrorReporting to enure that the client is
// closed down gracefully
func CloseClient() {
	if errorClient == nil {
		panic("The errorClient was nil, initialize it with InitErrorReporting before deferring this function")
	}
	var _ = errorClient.Close() // Ignoring this error
}

// Deprecated: The functionality is split into InitErrorReporting, ReportPanics and CloseClient instead
// SetUpErrorReporting creates an ErrorReporting client and returns that client together with a reportPanics function.
// That function should be defered in every new scope where you want to catch pancis and have them pass on to Stackdriver
// Error Reporting
func SetUpErrorReporting(ctx context.Context, projectID, serviceName, serviceVersion string) (client *errorreporting.Client, reportPanics func()) {
	lgr := New("errorreporting")
	errClient := InitErrorReporting(ctx, projectID, serviceName, serviceVersion)
	if errClient != nil {
		lgr.Fatal("Couldn't create an errorreporting client", errClient)
	}
	return errorClient, func() {
		x := recover()
		if x == nil {
			return
		}
		switch e := x.(type) {
		case string:
			err := errorClient.ReportSync(ctx, errorreporting.Entry{Error: errors.New(e)})
			if err != nil {
				lgr.Error("Couldn't do a ReportSync to Stackdriver Error Reporting", err)
			}
		}
		// repanics so the app execution stops
		lgr.Info("Re-panicking ", "err", x)
		panic(x)
	}
}

var defaultsSet bool
var mutex = sync.Mutex{}

func setDefaults() {
	// These configurations are made to make the
	// log payload compatible with the LogEntry format used in Google Cloud Logging
	// https://cloud.google.com/logging/docs/reference/v2/rest/v2/LogEntry
	log.KeyMap.Level = "severity"
	log.KeyMap.Message = "message"
	log.KeyMap.Time = "timestamp"
	log.LevelMap[log.LevelFatal] = "CRITICAL"
	log.LevelMap[log.LevelError] = "ERROR"
	log.LevelMap[log.LevelInfo] = "INFO"
	log.LevelMap[log.LevelDebug] = "DEBUG"
	defaultsSet = true
}

// New creates a new logger with the given (string) name
func New(name string) UnaLogger {
	return NewLogger(Config{Name: name})
}

// NewLogger creates a new logger with the given (Config) name
func NewLogger(conf Config) UnaLogger {

	logxiLogger := log.New(conf.Name)
	if conf.FileName != "" {
		if file, err := os.Create(conf.FileName); err == nil {
			logxiLogger = log.NewLogger(file, conf.Name)
		}
	}
	unaLogger := &unaLogger{
		Logger: logxiLogger,
		name:   conf.Name,
	}

	// Add the logger to the list of loggers and set some defaults
	// Needs to use a mutex here so loggers can be created in different goroutines
	mutex.Lock()
	loggers = append(loggers, unaLogger)
	if !defaultsSet {
		setDefaults()
	}
	mutex.Unlock()

	return unaLogger
}

// SetWriter overrides the io.Writer of the underlying logxi logger
func (ul *unaLogger) SetWriter(writer io.Writer) {
	ul.Logger = log.NewLogger(writer, ul.name)
}

// Underlying returns the underlying logxi logger
func (ul unaLogger) Underlying() log.Logger {
	return ul.Logger
}

// Info logs to Stdout with an "INFO" prefix
func (ul unaLogger) Info(msg string, args ...interface{}) {
	ul.Logger.Info(msg, args...)
}

// Debug logs to Stdout with an "DEBUG" prefix if Debug level is enabled
func (ul unaLogger) Debug(msg string, args ...interface{}) {
	ul.Logger.Debug(msg, args...)
}

// Error logs to Stdout with an "Error" prefix
// It also adds an "error" key to the provided err(error) argument
func (ul unaLogger) Error(msg string, err error, args ...interface{}) {
	if errorClient != nil {
		errorClient.Report(errorreporting.Entry{
			Error: err,
		})
	}
	_ = ul.Logger.Error(msg, appendErrorToArgs(args, err)...)
}

// Fatal logs to Stdout with an "Fatal" prefix
// It also adds an "error" key to the provided err(error) argument
func (ul unaLogger) Fatal(msg string, err error, args ...interface{}) {
	if errorClient != nil {
		defer ReportPanics(context.Background())()
		// Logging at level Fatal without the panic since we have reported to Errorreporting already
		ul.Logger.Log(log.LevelFatal, msg, appendErrorToArgs(args, err))
	}
	ul.Logger.Fatal(msg, appendErrorToArgs(args, err))
}

func appendErrorToArgs(args []interface{}, err error) []interface{} {
	return append(args, "error", err)
}
<commit_msg>Update missing loglevel translations for GCP<commit_after>package logger

import (
	"io"
	"os"

	"context"

	"sync"

	"cloud.google.com/go/errorreporting"
	log "github.com/mgutz/logxi/v1"
	"github.com/pkg/errors"
)

// UnaLogger wraps a logxi logger
// and delegate to some of it's logging methods
type UnaLogger interface {
	Debug(msg string, args ...interface{})
	Info(msg string, args ...interface{})
	Error(msg string, err error, args ...interface{})
	Fatal(msg string, err error, args ...interface{})
	Underlying() log.Logger
}

type unaLogger struct {
	Logger log.Logger
	name   string
}

// Config contains Name and FileName for the logger
type Config struct {
	Name     string
	FileName string
}

// Keep a list of loggers that we can use in the SetLevel func
var loggers []UnaLogger

var errorClient *errorreporting.Client

// logger for internal use
var lgr UnaLogger

// ExitOnPanic makes it possible to disable exiting in ReportPanics
var ExitOnPanic = true

// InitErrorReporting will enable the errors of all calls to Error and Fatal to be sent to Google Error Reporting
// It also enables the
func InitErrorReporting(ctx context.Context, projectID, serviceName, serviceVersion string) error {
	lgr = New("unalogger")
	client, err := errorreporting.NewClient(ctx, projectID,
		errorreporting.Config{
			ServiceName:    serviceName,
			ServiceVersion: serviceVersion})
	if err != nil {
		return err
	}

	errorClient = client

	return nil
}

// ReportPanics should be defered in every new scope where you want to catch pancis and have them pass on to Stackdriver
// Error Reporting
func ReportPanics(ctx context.Context) func() {
	return func() {
		if errorClient == nil {
			panic("The errorClient was nil, initialize it with InitErrorReporting before deferring this function")
		}
		x := recover()
		if x == nil {
			return
		}
		switch e := x.(type) {
		case string:
			err := errorClient.ReportSync(ctx, errorreporting.Entry{Error: errors.New(e)})
			if err != nil {
				lgr.Error("Couldn't do a ReportSync to Stackdriver Error Reporting", err)
			}
		case error:
			err := errorClient.ReportSync(ctx, errorreporting.Entry{Error: e})
			if err != nil {
				lgr.Error("Couldn't do a ReportSync to Stackdriver Error Reporting", err)
			}
		default:
			panic(x)
		}
		// exits with a non-zero code so the app execution stops
		if ExitOnPanic {
			os.Exit(1337)
		}
	}
}

// CloseClient should be deferred right after calling InitErrorReporting to enure that the client is
// closed down gracefully
func CloseClient() {
	if errorClient == nil {
		panic("The errorClient was nil, initialize it with InitErrorReporting before deferring this function")
	}
	var _ = errorClient.Close() // Ignoring this error
}

// Deprecated: The functionality is split into InitErrorReporting, ReportPanics and CloseClient instead
// SetUpErrorReporting creates an ErrorReporting client and returns that client together with a reportPanics function.
// That function should be defered in every new scope where you want to catch pancis and have them pass on to Stackdriver
// Error Reporting
func SetUpErrorReporting(ctx context.Context, projectID, serviceName, serviceVersion string) (client *errorreporting.Client, reportPanics func()) {
	lgr := New("errorreporting")
	errClient := InitErrorReporting(ctx, projectID, serviceName, serviceVersion)
	if errClient != nil {
		lgr.Fatal("Couldn't create an errorreporting client", errClient)
	}
	return errorClient, func() {
		x := recover()
		if x == nil {
			return
		}
		switch e := x.(type) {
		case string:
			err := errorClient.ReportSync(ctx, errorreporting.Entry{Error: errors.New(e)})
			if err != nil {
				lgr.Error("Couldn't do a ReportSync to Stackdriver Error Reporting", err)
			}
		}
		// repanics so the app execution stops
		lgr.Info("Re-panicking ", "err", x)
		panic(x)
	}
}

var defaultsSet bool
var mutex = sync.Mutex{}

func setDefaults() {
	// These configurations are made to make the
	// log payload compatible with the LogEntry format used in Google Cloud Logging
	// https://cloud.google.com/logging/docs/reference/v2/rest/v2/LogEntry
	log.KeyMap.Level = "severity"
	log.KeyMap.Message = "message"
	log.KeyMap.Time = "timestamp"
	log.LevelMap[log.LevelEmergency] = "EMERGENCY"
	log.LevelMap[log.LevelAlert] = "ALERT"
	log.LevelMap[log.LevelFatal] = "CRITICAL"
	log.LevelMap[log.LevelError] = "ERROR"
	log.LevelMap[log.LevelWarn] = "WARNING"
	log.LevelMap[log.LevelNotice] = "NOTICE"
	log.LevelMap[log.LevelInfo] = "INFO"
	log.LevelMap[log.LevelDebug] = "DEBUG"
	defaultsSet = true
}

// New creates a new logger with the given (string) name
func New(name string) UnaLogger {
	return NewLogger(Config{Name: name})
}

// NewLogger creates a new logger with the given (Config) name
func NewLogger(conf Config) UnaLogger {

	logxiLogger := log.New(conf.Name)
	if conf.FileName != "" {
		if file, err := os.Create(conf.FileName); err == nil {
			logxiLogger = log.NewLogger(file, conf.Name)
		}
	}
	unaLogger := &unaLogger{
		Logger: logxiLogger,
		name:   conf.Name,
	}

	// Add the logger to the list of loggers and set some defaults
	// Needs to use a mutex here so loggers can be created in different goroutines
	mutex.Lock()
	loggers = append(loggers, unaLogger)
	if !defaultsSet {
		setDefaults()
	}
	mutex.Unlock()

	return unaLogger
}

// SetWriter overrides the io.Writer of the underlying logxi logger
func (ul *unaLogger) SetWriter(writer io.Writer) {
	ul.Logger = log.NewLogger(writer, ul.name)
}

// Underlying returns the underlying logxi logger
func (ul unaLogger) Underlying() log.Logger {
	return ul.Logger
}

// Info logs to Stdout with an "INFO" prefix
func (ul unaLogger) Info(msg string, args ...interface{}) {
	ul.Logger.Info(msg, args...)
}

// Debug logs to Stdout with an "DEBUG" prefix if Debug level is enabled
func (ul unaLogger) Debug(msg string, args ...interface{}) {
	ul.Logger.Debug(msg, args...)
}

// Error logs to Stdout with an "Error" prefix
// It also adds an "error" key to the provided err(error) argument
func (ul unaLogger) Error(msg string, err error, args ...interface{}) {
	if errorClient != nil {
		errorClient.Report(errorreporting.Entry{
			Error: err,
		})
	}
	_ = ul.Logger.Error(msg, appendErrorToArgs(args, err)...)
}

// Fatal logs to Stdout with an "Fatal" prefix
// It also adds an "error" key to the provided err(error) argument
func (ul unaLogger) Fatal(msg string, err error, args ...interface{}) {
	if errorClient != nil {
		defer ReportPanics(context.Background())()
		// Logging at level Fatal without the panic since we have reported to Errorreporting already
		ul.Logger.Log(log.LevelFatal, msg, appendErrorToArgs(args, err))
	}
	ul.Logger.Fatal(msg, appendErrorToArgs(args, err))
}

func appendErrorToArgs(args []interface{}, err error) []interface{} {
	return append(args, "error", err)
}
<|endoftext|>


<commit_before>package logrus

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

type Logger struct {
	// The logs are `io.Copy`'d to this in a mutex. It's common to set this to a
	// file, or leave it default which is `os.Stderr`. You can also set this to
	// something more adventorous, such as logging to Kafka.
	Out io.Writer
	// Hooks for the logger instance. These allow firing events based on logging
	// levels and log entries. For example, to send errors to an error tracking
	// service, log to StatsD or dump the core on fatal errors.
	Hooks LevelHooks
	// All log entries pass through the formatter before logged to Out. The
	// included formatters are `TextFormatter` and `JSONFormatter` for which
	// TextFormatter is the default. In development (when a TTY is attached) it
	// logs with colors, but to a file it wouldn't. You can easily implement your
	// own that implements the `Formatter` interface, see the `README` or included
	// formatters for examples.
	Formatter Formatter
	// The logging level the logger should log at. This is typically (and defaults
	// to) `logrus.Info`, which allows Info(), Warn(), Error() and Fatal() to be
	// logged.
	Level Level
	// Used to sync writing to the log. Locking is enabled by Default
	mu MutexWrap
	// Reusable empty entry
	entryPool sync.Pool
}

type MutexWrap struct {
	lock     sync.Mutex
	disabled bool
}

func (mw *MutexWrap) Lock() {
	if !mw.disabled {
		mw.lock.Lock()
	}
}

func (mw *MutexWrap) Unlock() {
	if !mw.disabled {
		mw.lock.Unlock()
	}
}

func (mw *MutexWrap) Disable() {
	mw.disabled = true
}

// Creates a new logger. Configuration should be set by changing `Formatter`,
// `Out` and `Hooks` directly on the default logger instance. You can also just
// instantiate your own:
//
//    var log = &Logger{
//      Out: os.Stderr,
//      Formatter: new(JSONFormatter),
//      Hooks: make(LevelHooks),
//      Level: logrus.DebugLevel,
//    }
//
// It's recommended to make this a global instance called `log`.
func New() *Logger {
	return &Logger{
		Out:       os.Stderr,
		Formatter: new(TextFormatter),
		Hooks:     make(LevelHooks),
		Level:     InfoLevel,
	}
}

func (logger *Logger) newEntry() *Entry {
	entry, ok := logger.entryPool.Get().(*Entry)
	if ok {
		return entry
	}
	return NewEntry(logger)
}

func (logger *Logger) releaseEntry(entry *Entry) {
	logger.entryPool.Put(entry)
}

// Adds a field to the log entry, note that it doesn't log until you call
// Debug, Print, Info, Warn, Fatal or Panic. It only creates a log entry.
// If you want multiple fields, use `WithFields`.
func (logger *Logger) WithField(key string, value interface{}) *Entry {
	entry := logger.newEntry()
	defer logger.releaseEntry(entry)
	return entry.WithField(key, value)
}

// Adds a struct of fields to the log entry. All it does is call `WithField` for
// each `Field`.
func (logger *Logger) WithFields(fields Fields) *Entry {
	entry := logger.newEntry()
	defer logger.releaseEntry(entry)
	return entry.WithFields(fields)
}

// Add an error as single field to the log entry.  All it does is call
// `WithError` for the given `error`.
func (logger *Logger) WithError(err error) *Entry {
	entry := logger.newEntry()
	defer logger.releaseEntry(entry)
	return entry.WithError(err)
}

func (logger *Logger) Debugf(format string, args ...interface{}) {
	if logger.level() >= DebugLevel {
		entry := logger.newEntry()
		entry.Debugf(format, args...)
		logger.releaseEntry(entry)
	}
}

func (logger *Logger) Infof(format string, args ...interface{}) {
	if logger.level() >= InfoLevel {
		entry := logger.newEntry()
		entry.Infof(format, args...)
		logger.releaseEntry(entry)
	}
}

func (logger *Logger) Printf(format string, args ...interface{}) {
	entry := logger.newEntry()
	entry.Printf(format, args...)
	logger.releaseEntry(entry)
}

func (logger *Logger) Warnf(format string, args ...interface{}) {
	if logger.level() >= WarnLevel {
		entry := logger.newEntry()
		entry.Warnf(format, args...)
		logger.releaseEntry(entry)
	}
}

func (logger *Logger) Warningf(format string, args ...interface{}) {
	if logger.level() >= WarnLevel {
		entry := logger.newEntry()
		entry.Warnf(format, args...)
		logger.releaseEntry(entry)
	}
}

func (logger *Logger) Errorf(format string, args ...interface{}) {
	if logger.level() >= ErrorLevel {
		entry := logger.newEntry()
		entry.Errorf(format, args...)
		logger.releaseEntry(entry)
	}
}

func (logger *Logger) Fatalf(format string, args ...interface{}) {
	if logger.level() >= FatalLevel {
		entry := logger.newEntry()
		entry.Fatalf(format, args...)
		logger.releaseEntry(entry)
	}
	Exit(1)
}

func (logger *Logger) Panicf(format string, args ...interface{}) {
	if logger.level() >= PanicLevel {
		entry := logger.newEntry()
		entry.Panicf(format, args...)
		logger.releaseEntry(entry)
	}
}

func (logger *Logger) Debug(args ...interface{}) {
	if logger.level() >= DebugLevel {
		entry := logger.newEntry()
		entry.Debug(args...)
		logger.releaseEntry(entry)
	}
}

func (logger *Logger) Info(args ...interface{}) {
	if logger.level() >= InfoLevel {
		entry := logger.newEntry()
		entry.Info(args...)
		logger.releaseEntry(entry)
	}
}

func (logger *Logger) Print(args ...interface{}) {
	entry := logger.newEntry()
	entry.Info(args...)
	logger.releaseEntry(entry)
}

func (logger *Logger) Warn(args ...interface{}) {
	if logger.level() >= WarnLevel {
		entry := logger.newEntry()
		entry.Warn(args...)
		logger.releaseEntry(entry)
	}
}

func (logger *Logger) Warning(args ...interface{}) {
	if logger.level() >= WarnLevel {
		entry := logger.newEntry()
		entry.Warn(args...)
		logger.releaseEntry(entry)
	}
}

func (logger *Logger) Error(args ...interface{}) {
	if logger.level() >= ErrorLevel {
		entry := logger.newEntry()
		entry.Error(args...)
		logger.releaseEntry(entry)
	}
}

func (logger *Logger) Fatal(args ...interface{}) {
	if logger.level() >= FatalLevel {
		entry := logger.newEntry()
		entry.Fatal(args...)
		logger.releaseEntry(entry)
	}
	Exit(1)
}

func (logger *Logger) Panic(args ...interface{}) {
	if logger.level() >= PanicLevel {
		entry := logger.newEntry()
		entry.Panic(args...)
		logger.releaseEntry(entry)
	}
}

func (logger *Logger) Debugln(args ...interface{}) {
	if logger.level() >= DebugLevel {
		entry := logger.newEntry()
		entry.Debugln(args...)
		logger.releaseEntry(entry)
	}
}

func (logger *Logger) Infoln(args ...interface{}) {
	if logger.level() >= InfoLevel {
		entry := logger.newEntry()
		entry.Infoln(args...)
		logger.releaseEntry(entry)
	}
}

func (logger *Logger) Println(args ...interface{}) {
	entry := logger.newEntry()
	entry.Println(args...)
	logger.releaseEntry(entry)
}

func (logger *Logger) Warnln(args ...interface{}) {
	if logger.level() >= WarnLevel {
		entry := logger.newEntry()
		entry.Warnln(args...)
		logger.releaseEntry(entry)
	}
}

func (logger *Logger) Warningln(args ...interface{}) {
	if logger.level() >= WarnLevel {
		entry := logger.newEntry()
		entry.Warnln(args...)
		logger.releaseEntry(entry)
	}
}

func (logger *Logger) Errorln(args ...interface{}) {
	if logger.level() >= ErrorLevel {
		entry := logger.newEntry()
		entry.Errorln(args...)
		logger.releaseEntry(entry)
	}
}

func (logger *Logger) Fatalln(args ...interface{}) {
	if logger.level() >= FatalLevel {
		entry := logger.newEntry()
		entry.Fatalln(args...)
		logger.releaseEntry(entry)
	}
	Exit(1)
}

func (logger *Logger) Panicln(args ...interface{}) {
	if logger.level() >= PanicLevel {
		entry := logger.newEntry()
		entry.Panicln(args...)
		logger.releaseEntry(entry)
	}
}

//When file is opened with appending mode, it's safe to
//write concurrently to a file (within 4k message on Linux).
//In these cases user can choose to disable the lock.
func (logger *Logger) SetNoLock() {
	logger.mu.Disable()
}

func (logger *Logger) level() Level {
	return Level(atomic.LoadUint32((*uint32)(&logger.Level)))
}

func (logger *Logger) SetLevel(level Level) {
	atomic.StoreUint32((*uint32)(&logger.Level), uint32(level))
}

func (logger *Logger) AddHook(hook Hook) {
	logger.mu.Lock()
	defer logger.mu.Unlock()
	logger.Hooks.Add(hook)
}
<commit_msg>Fix Logger.WithField doscription<commit_after>package logrus

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

type Logger struct {
	// The logs are `io.Copy`'d to this in a mutex. It's common to set this to a
	// file, or leave it default which is `os.Stderr`. You can also set this to
	// something more adventorous, such as logging to Kafka.
	Out io.Writer
	// Hooks for the logger instance. These allow firing events based on logging
	// levels and log entries. For example, to send errors to an error tracking
	// service, log to StatsD or dump the core on fatal errors.
	Hooks LevelHooks
	// All log entries pass through the formatter before logged to Out. The
	// included formatters are `TextFormatter` and `JSONFormatter` for which
	// TextFormatter is the default. In development (when a TTY is attached) it
	// logs with colors, but to a file it wouldn't. You can easily implement your
	// own that implements the `Formatter` interface, see the `README` or included
	// formatters for examples.
	Formatter Formatter
	// The logging level the logger should log at. This is typically (and defaults
	// to) `logrus.Info`, which allows Info(), Warn(), Error() and Fatal() to be
	// logged.
	Level Level
	// Used to sync writing to the log. Locking is enabled by Default
	mu MutexWrap
	// Reusable empty entry
	entryPool sync.Pool
}

type MutexWrap struct {
	lock     sync.Mutex
	disabled bool
}

func (mw *MutexWrap) Lock() {
	if !mw.disabled {
		mw.lock.Lock()
	}
}

func (mw *MutexWrap) Unlock() {
	if !mw.disabled {
		mw.lock.Unlock()
	}
}

func (mw *MutexWrap) Disable() {
	mw.disabled = true
}

// Creates a new logger. Configuration should be set by changing `Formatter`,
// `Out` and `Hooks` directly on the default logger instance. You can also just
// instantiate your own:
//
//    var log = &Logger{
//      Out: os.Stderr,
//      Formatter: new(JSONFormatter),
//      Hooks: make(LevelHooks),
//      Level: logrus.DebugLevel,
//    }
//
// It's recommended to make this a global instance called `log`.
func New() *Logger {
	return &Logger{
		Out:       os.Stderr,
		Formatter: new(TextFormatter),
		Hooks:     make(LevelHooks),
		Level:     InfoLevel,
	}
}

func (logger *Logger) newEntry() *Entry {
	entry, ok := logger.entryPool.Get().(*Entry)
	if ok {
		return entry
	}
	return NewEntry(logger)
}

func (logger *Logger) releaseEntry(entry *Entry) {
	logger.entryPool.Put(entry)
}

// Adds a field to the log entry, note that it doesn't log until you call
// Debug, Print, Info, Warn, Error, Fatal or Panic. It only creates a log entry.
// If you want multiple fields, use `WithFields`.
func (logger *Logger) WithField(key string, value interface{}) *Entry {
	entry := logger.newEntry()
	defer logger.releaseEntry(entry)
	return entry.WithField(key, value)
}

// Adds a struct of fields to the log entry. All it does is call `WithField` for
// each `Field`.
func (logger *Logger) WithFields(fields Fields) *Entry {
	entry := logger.newEntry()
	defer logger.releaseEntry(entry)
	return entry.WithFields(fields)
}

// Add an error as single field to the log entry.  All it does is call
// `WithError` for the given `error`.
func (logger *Logger) WithError(err error) *Entry {
	entry := logger.newEntry()
	defer logger.releaseEntry(entry)
	return entry.WithError(err)
}

func (logger *Logger) Debugf(format string, args ...interface{}) {
	if logger.level() >= DebugLevel {
		entry := logger.newEntry()
		entry.Debugf(format, args...)
		logger.releaseEntry(entry)
	}
}

func (logger *Logger) Infof(format string, args ...interface{}) {
	if logger.level() >= InfoLevel {
		entry := logger.newEntry()
		entry.Infof(format, args...)
		logger.releaseEntry(entry)
	}
}

func (logger *Logger) Printf(format string, args ...interface{}) {
	entry := logger.newEntry()
	entry.Printf(format, args...)
	logger.releaseEntry(entry)
}

func (logger *Logger) Warnf(format string, args ...interface{}) {
	if logger.level() >= WarnLevel {
		entry := logger.newEntry()
		entry.Warnf(format, args...)
		logger.releaseEntry(entry)
	}
}

func (logger *Logger) Warningf(format string, args ...interface{}) {
	if logger.level() >= WarnLevel {
		entry := logger.newEntry()
		entry.Warnf(format, args...)
		logger.releaseEntry(entry)
	}
}

func (logger *Logger) Errorf(format string, args ...interface{}) {
	if logger.level() >= ErrorLevel {
		entry := logger.newEntry()
		entry.Errorf(format, args...)
		logger.releaseEntry(entry)
	}
}

func (logger *Logger) Fatalf(format string, args ...interface{}) {
	if logger.level() >= FatalLevel {
		entry := logger.newEntry()
		entry.Fatalf(format, args...)
		logger.releaseEntry(entry)
	}
	Exit(1)
}

func (logger *Logger) Panicf(format string, args ...interface{}) {
	if logger.level() >= PanicLevel {
		entry := logger.newEntry()
		entry.Panicf(format, args...)
		logger.releaseEntry(entry)
	}
}

func (logger *Logger) Debug(args ...interface{}) {
	if logger.level() >= DebugLevel {
		entry := logger.newEntry()
		entry.Debug(args...)
		logger.releaseEntry(entry)
	}
}

func (logger *Logger) Info(args ...interface{}) {
	if logger.level() >= InfoLevel {
		entry := logger.newEntry()
		entry.Info(args...)
		logger.releaseEntry(entry)
	}
}

func (logger *Logger) Print(args ...interface{}) {
	entry := logger.newEntry()
	entry.Info(args...)
	logger.releaseEntry(entry)
}

func (logger *Logger) Warn(args ...interface{}) {
	if logger.level() >= WarnLevel {
		entry := logger.newEntry()
		entry.Warn(args...)
		logger.releaseEntry(entry)
	}
}

func (logger *Logger) Warning(args ...interface{}) {
	if logger.level() >= WarnLevel {
		entry := logger.newEntry()
		entry.Warn(args...)
		logger.releaseEntry(entry)
	}
}

func (logger *Logger) Error(args ...interface{}) {
	if logger.level() >= ErrorLevel {
		entry := logger.newEntry()
		entry.Error(args...)
		logger.releaseEntry(entry)
	}
}

func (logger *Logger) Fatal(args ...interface{}) {
	if logger.level() >= FatalLevel {
		entry := logger.newEntry()
		entry.Fatal(args...)
		logger.releaseEntry(entry)
	}
	Exit(1)
}

func (logger *Logger) Panic(args ...interface{}) {
	if logger.level() >= PanicLevel {
		entry := logger.newEntry()
		entry.Panic(args...)
		logger.releaseEntry(entry)
	}
}

func (logger *Logger) Debugln(args ...interface{}) {
	if logger.level() >= DebugLevel {
		entry := logger.newEntry()
		entry.Debugln(args...)
		logger.releaseEntry(entry)
	}
}

func (logger *Logger) Infoln(args ...interface{}) {
	if logger.level() >= InfoLevel {
		entry := logger.newEntry()
		entry.Infoln(args...)
		logger.releaseEntry(entry)
	}
}

func (logger *Logger) Println(args ...interface{}) {
	entry := logger.newEntry()
	entry.Println(args...)
	logger.releaseEntry(entry)
}

func (logger *Logger) Warnln(args ...interface{}) {
	if logger.level() >= WarnLevel {
		entry := logger.newEntry()
		entry.Warnln(args...)
		logger.releaseEntry(entry)
	}
}

func (logger *Logger) Warningln(args ...interface{}) {
	if logger.level() >= WarnLevel {
		entry := logger.newEntry()
		entry.Warnln(args...)
		logger.releaseEntry(entry)
	}
}

func (logger *Logger) Errorln(args ...interface{}) {
	if logger.level() >= ErrorLevel {
		entry := logger.newEntry()
		entry.Errorln(args...)
		logger.releaseEntry(entry)
	}
}

func (logger *Logger) Fatalln(args ...interface{}) {
	if logger.level() >= FatalLevel {
		entry := logger.newEntry()
		entry.Fatalln(args...)
		logger.releaseEntry(entry)
	}
	Exit(1)
}

func (logger *Logger) Panicln(args ...interface{}) {
	if logger.level() >= PanicLevel {
		entry := logger.newEntry()
		entry.Panicln(args...)
		logger.releaseEntry(entry)
	}
}

//When file is opened with appending mode, it's safe to
//write concurrently to a file (within 4k message on Linux).
//In these cases user can choose to disable the lock.
func (logger *Logger) SetNoLock() {
	logger.mu.Disable()
}

func (logger *Logger) level() Level {
	return Level(atomic.LoadUint32((*uint32)(&logger.Level)))
}

func (logger *Logger) SetLevel(level Level) {
	atomic.StoreUint32((*uint32)(&logger.Level), uint32(level))
}

func (logger *Logger) AddHook(hook Hook) {
	logger.mu.Lock()
	defer logger.mu.Unlock()
	logger.Hooks.Add(hook)
}
<|endoftext|>


<commit_before>package lily

// Author João Nuno.
//
// joaonrb@gmail.com
//

import (
	"fmt"
	"github.com/op/go-logging"
	"io"
	"os"
	"os/signal"
	"strings"
	"syscall"
)

var log = logging.MustGetLogger("lily")

func init() {
	log.ExtraCalldepth = 1
}

const (
	loggerPermissions = 0666
)

const (
	CONSOLE = "console" // console logging
	FILE    = "file"    // file Logging
)

const (
	CRITICAL = "critical" // critical level
	ERROR    = "error"    // error level
	WARNING  = "warning"  // warning level
	INFO     = "info"     // info level
	DEBUG    = "debug"    // debug level
)

// Log default settings
const (
	defaultLoggerType   = "console"
	defaultLoggerPath   = ""
	defaultLoggerLayout = "%{level:.4s} %{time:2006-01-02 15:04:05.000} %{shortfile} %{message}"
	defaultLoggerLevel  = INFO
)

var (
	// Logging map of levels
	LOGGING_LEVELS = map[string]logging.Level{
		CRITICAL: logging.CRITICAL,
		ERROR:    logging.ERROR,
		WARNING:  logging.WARNING,
		INFO:     logging.INFO,
		DEBUG:    logging.DEBUG,
	}
)

// Critical logging
func Critical(message string, args ...interface{}) {
	log.Critical(message, args...)
}

// Error logging
func Error(message string, args ...interface{}) {
	log.Error(message, args...)
}

// Warning logging
func Warning(message string, args ...interface{}) {
	log.Warning(message, args...)
}

// Info logging
func Info(message string, args ...interface{}) {
	log.Info(message, args...)
}

// Notice logging
func Notice(message string, args ...interface{}) {
	log.Notice(message, args...)
}

// Debug logging
func Debug(message string, args ...interface{}) {
	log.Debug(message, args...)
}

// Load logger
func LoadLogger(loggers []SLogger) {
	var out io.Writer
	goLoggers := make([]logging.Backend, 0)
	for _, loggerSettings := range loggers {
		switch loggerSettings.Type {
		case CONSOLE:
			out = os.Stdout
		case FILE:
			out = OpenRotatoryWriter(loggerSettings.Path)
		}
		logger := logging.NewLogBackend(out, "", 0)
		beFormatter := logging.NewBackendFormatter(logger, logging.MustStringFormatter(loggerSettings.Layout))
		beLevel := logging.AddModuleLevel(beFormatter)

		// Set Level
		lowerCaseLevel := strings.ToLower(loggerSettings.Level)
		levelNumber := LOGGING_LEVELS[lowerCaseLevel]
		beLevel.SetLevel(levelNumber, "")
		goLoggers = append(goLoggers, beLevel)
	}
	log.SetBackend(logging.MultiLogger(goLoggers...))
}

// Rotate writer
type RotatoryWriter struct {
	doRotation bool
	file       *os.File
	filePath   string
}

// Open the writer
func OpenRotatoryWriter(path string) io.Writer {
	out, err := os.OpenFile(path, os.O_CREATE|os.O_WRONLY|os.O_APPEND, loggerPermissions)
	if err != nil {
		panic(
			fmt.Errorf(
				"Failed to open log file %s with permissions %d: %s", path, loggerPermissions, err,
			),
		)
	}
	rotatoryWriter := &RotatoryWriter{doRotation: false, file: out, filePath: path}
	c := make(chan os.Signal, 1)
	signal.Notify(c, syscall.SIGUSR1)
	go func(rot *RotatoryWriter) {
		for {
			<-c
			rotatoryWriter.doRotation = true
			Info("Rotate order caught for file '%s'", path)
		}
	}(rotatoryWriter)
	return rotatoryWriter
}

// Write on file
func (writer *RotatoryWriter) Write(p []byte) (n int, err error) {
	if writer.doRotation {
		writer.doRotation = false
		writer.file.Close()
		out, err := os.OpenFile(writer.filePath, os.O_CREATE|os.O_WRONLY|os.O_APPEND, loggerPermissions)
		if err != nil {
			panic(
				fmt.Errorf(
					"Failed to open log file %s with permissions %d: %s", writer.filePath, loggerPermissions, err,
				),
			)
		}
		writer.file = out
	}
	return writer.file.Write(p)
}
<commit_msg>Quick fix<commit_after>package lily

// Author João Nuno.
//
// joaonrb@gmail.com
//

import (
	"fmt"
	"github.com/op/go-logging"
	"io"
	"os"
	"os/signal"
	"strings"
	"syscall"
)

var log = logging.MustGetLogger("lily")

func init() {
	log.ExtraCalldepth = 1
}

const (
	loggerPermissions = 0666
)

const (
	CONSOLE = "console" // console logging
	FILE    = "file"    // file Logging
)

const (
	CRITICAL = "critical" // critical level
	ERROR    = "error"    // error level
	WARNING  = "warning"  // warning level
	INFO     = "info"     // info level
	DEBUG    = "debug"    // debug level
)

// Log default settings
const (
	defaultLoggerType   = "console"
	defaultLoggerPath   = ""
	defaultLoggerLayout = "%{level:.4s} %{time:2006-01-02 15:04:05.000} %{shortfile} %{message}"
	defaultLoggerLevel  = INFO
)

var (
	// Logging map of levels
	LOGGING_LEVELS = map[string]logging.Level{
		CRITICAL: logging.CRITICAL,
		ERROR:    logging.ERROR,
		WARNING:  logging.WARNING,
		INFO:     logging.INFO,
		DEBUG:    logging.DEBUG,
	}
)

// Critical logging
func Critical(message string, args ...interface{}) {
	log.Criticalf(message, args...)
}

// Error logging
func Error(message string, args ...interface{}) {
	log.Errorf(message, args...)
}

// Warning logging
func Warning(message string, args ...interface{}) {
	log.Warningf(message, args...)
}

// Info logging
func Info(message string, args ...interface{}) {
	log.Infof(message, args...)
}

// Notice logging
func Notice(message string, args ...interface{}) {
	log.Noticef(message, args...)
}

// Debug logging
func Debug(message string, args ...interface{}) {
	log.Debugf(message, args...)
}

// Load logger
func LoadLogger(loggers []SLogger) {
	var out io.Writer
	goLoggers := make([]logging.Backend, 0)
	for _, loggerSettings := range loggers {
		switch loggerSettings.Type {
		case CONSOLE:
			out = os.Stdout
		case FILE:
			out = OpenRotatoryWriter(loggerSettings.Path)
		}
		logger := logging.NewLogBackend(out, "", 0)
		beFormatter := logging.NewBackendFormatter(logger, logging.MustStringFormatter(loggerSettings.Layout))
		beLevel := logging.AddModuleLevel(beFormatter)

		// Set Level
		lowerCaseLevel := strings.ToLower(loggerSettings.Level)
		levelNumber := LOGGING_LEVELS[lowerCaseLevel]
		beLevel.SetLevel(levelNumber, "")
		goLoggers = append(goLoggers, beLevel)
	}
	log.SetBackend(logging.MultiLogger(goLoggers...))
}

// Rotate writer
type RotatoryWriter struct {
	doRotation bool
	file       *os.File
	filePath   string
}

// Open the writer
func OpenRotatoryWriter(path string) io.Writer {
	out, err := os.OpenFile(path, os.O_CREATE|os.O_WRONLY|os.O_APPEND, loggerPermissions)
	if err != nil {
		panic(
			fmt.Errorf(
				"Failed to open log file %s with permissions %d: %s", path, loggerPermissions, err,
			),
		)
	}
	rotatoryWriter := &RotatoryWriter{doRotation: false, file: out, filePath: path}
	c := make(chan os.Signal, 1)
	signal.Notify(c, syscall.SIGUSR1)
	go func(rot *RotatoryWriter) {
		for {
			<-c
			rotatoryWriter.doRotation = true
			Info("Rotate order caught for file '%s'", path)
		}
	}(rotatoryWriter)
	return rotatoryWriter
}

// Write on file
func (writer *RotatoryWriter) Write(p []byte) (n int, err error) {
	if writer.doRotation {
		writer.doRotation = false
		writer.file.Close()
		out, err := os.OpenFile(writer.filePath, os.O_CREATE|os.O_WRONLY|os.O_APPEND, loggerPermissions)
		if err != nil {
			panic(
				fmt.Errorf(
					"Failed to open log file %s with permissions %d: %s", writer.filePath, loggerPermissions, err,
				),
			)
		}
		writer.file = out
	}
	return writer.file.Write(p)
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"log"
	"os"
	"os/exec"
)

var (
	title = flag.String("t", "Utility Name", "Title of notification.")
	mesg  = flag.String("m", "Done!", "Message notification will display.")
	sound = flag.String("s", "Ping", "Sound to play when notified.")
)

func init() {
	flag.Usage = func() {
		fmt.Fprintln(os.Stderr, `Usage: noti [-tms] <utility> [args...]

    -t    Title of notification. Default is the utility name.

    -m    Message notification will display. Default is "Done!"

    -s    Sound to play when notified. Default is Ping. Possible options
          are Basso, Blow, Bottle, Frog, Funk, Glass, Hero, Morse, Ping,
          Pop, Purr, Sosumi, Submarine, Tink. Check /System/Library/Sounds
          for more info.

    -h    Display usage information and exit.`)
	}
}

func main() {
	flag.Parse()

	if len(flag.Args()) == 0 {
		flag.Usage()
		return
	}

	if *title == "Utility Name" {
		*title = flag.Args()[0]
	}

	if err := Exec(flag.Args()[0], flag.Args()[1:]); err != nil {
		Notify(*title, "Failed. See terminal.", "Basso")
		return
	}

	if err := Notify(*title, *mesg, *sound); err != nil {
		log.Println(err)
	}
}

// Exec executes a program. The stdout and stderr of the executing program are
// sent to noti.
func Exec(bin string, args []string) error {
	cmd := exec.Command(bin, args...)
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr

	return cmd.Run()
}

// Notify displays a notification in OS X's notification center with a given
// title, message, and sound.
func Notify(title, mesg, sound string) error {
	script := fmt.Sprintf("display notification %q with title %q sound name %q",
		mesg, title, sound)

	cmd := exec.Command("osascript", "-e", script)
	return cmd.Run()
}
<commit_msg>Pass os.stdin to utility.stdin.<commit_after>package main

import (
	"flag"
	"fmt"
	"log"
	"os"
	"os/exec"
)

var (
	title = flag.String("t", "Utility Name", "Title of notification.")
	mesg  = flag.String("m", "Done!", "Message notification will display.")
	sound = flag.String("s", "Ping", "Sound to play when notified.")
)

func init() {
	flag.Usage = func() {
		fmt.Fprintln(os.Stderr, `Usage: noti [-tms] <utility> [args...]

    -t    Title of notification. Default is the utility name.

    -m    Message notification will display. Default is "Done!"

    -s    Sound to play when notified. Default is Ping. Possible options
          are Basso, Blow, Bottle, Frog, Funk, Glass, Hero, Morse, Ping,
          Pop, Purr, Sosumi, Submarine, Tink. Check /System/Library/Sounds
          for more info.

    -h    Display usage information and exit.`)
	}
}

func main() {
	flag.Parse()

	if len(flag.Args()) == 0 {
		flag.Usage()
		return
	}

	if *title == "Utility Name" {
		*title = flag.Args()[0]
	}

	if err := Exec(flag.Args()[0], flag.Args()[1:]); err != nil {
		Notify(*title, "Failed. See terminal.", "Basso")
		return
	}

	if err := Notify(*title, *mesg, *sound); err != nil {
		log.Println(err)
	}
}

// Exec executes a program. The stdout and stderr of the executing program are
// sent to noti.
func Exec(bin string, args []string) error {
	cmd := exec.Command(bin, args...)
	cmd.Stdin = os.Stdin
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr

	return cmd.Run()
}

// Notify displays a notification in OS X's notification center with a given
// title, message, and sound.
func Notify(title, mesg, sound string) error {
	script := fmt.Sprintf("display notification %q with title %q sound name %q",
		mesg, title, sound)

	cmd := exec.Command("osascript", "-e", script)
	return cmd.Run()
}
<|endoftext|>