<commit_before>package gojenkins

import "encoding/xml"

type Artifact struct {
	DisplayPath  string `json:"displayPath"`
	FileName     string `json:"fileName"`
	RelativePath string `json:"relativePath"`
}

type ScmAuthor struct {
	FullName    string `json:"fullName"`
	AbsoluteUrl string `json:"absoluteUrl"`
}

type ScmChangeSetPath struct {
	EditType string `json:"editType"`
	File     string `json:"File"`
}

type ChangeSetItem struct {
	AffectedPaths []string           `json:"affectedPaths"`
	CommitId      string             `json:"commitId"`
	Timestamp     int                `json:"timestamp"`
	Author        ScmAuthor          `json:"author"`
	Comment       string             `json:"comment"`
	Date          string             `json:"date"`
	Id            string             `json:"id"`
	Message       string             `json:"msg"`
	Paths         []ScmChangeSetPath `json:"paths"`
}

type ScmChangeSet struct {
	Kind  string          `json:"kind"`
	Items []ChangeSetItem `json:"items"`
}

type Build struct {
	Id     string `json:"id"`
	Number int    `json:"number"`
	Url    string `json:"url"`

	FullDisplayName string `json:"fullDisplayName"`
	Description     string `json:"description"`

	Timestamp         int `json:"timestamp"`
	Duration          int `json:"duration"`
	EstimatedDuration int `json:"estimatedDuration"`

	Building bool   `json:"building"`
	KeepLog  bool   `json:"keepLog"`
	Result   string `json:"result"`

	Artifacts []Artifact `json:"artifacts"`
	Actions   []Action   `json:"actions"`

	ChangeSet ScmChangeSet `json:"changeSet"`
}

type UpstreamCause struct {
	ShortDescription string `json:"shortDescription"`
	UpstreamBuild    int    `json:"upstreamBuild"`
	UpstreamProject  string `json:"upstreamProject"`
	UpstreamUrl      string `json:"upstreamUrl"`
}

type Job struct {
	Actions []Action `json:"actions"`
	Name    string   `json:"name"`
	Url     string   `json:"url"`
	Color   string   `json:"color"`

	Buildable    bool     `json:"buildable"`
	DisplayName  string   `json:"displayName"`
	Description  string   `json:"description"`
	HealthReport []Health `json:"healthReport"`

	LastCompletedBuild    Build `json:"lastCompletedBuild"`
	LastFailedBuild       Build `json:"lastFailedBuild"`
	LastStableBuild       Build `json:"lastStableBuild"`
	LastSuccessfulBuild   Build `json:"lastSuccessfulBuild"`
	LastUnstableBuild     Build `json:"lastUnstableBuild"`
	LastUnsuccessfulBuild Build `json:"lastUnsuccessfulBuild"`
}

type Health struct {
	Description string `json:"description"`
}

type MavenJobItem struct {
	XMLName                          struct{}             `xml:"maven2-moduleset"`
	Plugin                           string               `xml:"plugin,attr"`
	Actions                          string               `xml:"actions"`
	Description                      string               `xml:"description"`
	KeepDependencies                 string               `xml:"keepDependencies"`
	Properties                       JobProperties        `xml:"properties"`
	Scm                              Scm                  `xml:"scm"`
	CanRoam                          string               `xml:"canRoam"`
	Disabled                         string               `xml:"disabled"`
	BlockBuildWhenDownstreamBuilding string               `xml:"blockBuildWhenDownstreamBuilding"`
	BlockBuildWhenUpstreamBuilding   string               `xml:"blockBuildWhenUpstreamBuilding"`
	Triggers                         Triggers             `xml:"triggers"`
	ConcurrentBuild                  string               `xml:"concurrentBuild"`
	Goals                            string               `xml:"goals"`
	AggregatorStyleBuild             string               `xml:"aggregatorStyleBuild"`
	IncrementalBuild                 string               `xml:"incrementalBuild"`
	IgnoreUpstremChanges             string               `xml:"ignoreUpstremChanges"`
	ArchivingDisabled                string               `xml:"archivingDisabled"`
	SiteArchivingDisabled            string               `xml:"siteArchivingDisabled"`
	FingerprintingDisabled           string               `xml:"fingerprintingDisabled"`
	ResolveDependencies              string               `xml:"resolveDependencies"`
	ProcessPlugins                   string               `xml:"processPlugins"`
	MavenName                        string               `xml:"mavenName"`
	MavenValidationLevel             string               `xml:"mavenValidationLevel"`
	DefaultGoals                     string               `xml:"defaultGoals"`
	RunHeadless                      string               `xml:"runHeadless"`
	DisableTriggerDownstreamProjects string               `xml:"disableTriggerDownstreamProjects"`
	Settings                         JobSettings          `xml:"settings"`
	GlobalSettings                   JobSettings          `xml:"globalSettings"`
	RunPostStepsIfResult             RunPostStepsIfResult `xml:"runPostStepsIfResult"`
	Postbuilders                     PostBuilders         `xml:"postbuilders"`
}

type Scm struct {
	ScmContent
	Class  string `xml:"class,attr"`
	Plugin string `xml:"plugin,attr"`
}

type ScmContent interface{}

type ScmSvn struct {
	Locations              Locations        `xml:"locations"`
	ExcludedRegions        string           `xml:"excludedRegions"`
	IncludedRegions        string           `xml:"includedRegions"`
	ExcludedUsers          string           `xml:"excludedUsers"`
	ExcludedRevprop        string           `xml:"excludedRevprop"`
	ExcludedCommitMessages string           `xml:"excludedCommitMessages"`
	WorkspaceUpdater       WorkspaceUpdater `xml:"workspaceUpdater"`
	IgnoreDirPropChanges   string           `xml:"ignoreDirPropChanges"`
	FilterChangelog        string           `xml:"filterChangelog"`
}

type WorkspaceUpdater struct {
	Class string `xml:"class,attr"`
}
type Locations struct {
	Location []ScmSvnLocation `xml:"hudson.scm.SubversionSCM_-ModuleLocation"`
}

type ScmSvnLocation struct {
	Remote                string `xml:"remote"`
	Local                 string `xml:"local"`
	DepthOption           string `xml:"depthOption"`
	IgnoreExternalsOption string `xml:"ignoreExternalsOption"`
}

type PostBuilders struct {
	XMLName     xml.Name `xml:"postbuilders"`
	PostBuilder []PostBuilder
}

type PostBuilder interface {
}

type ShellBuilder struct {
	XMLName xml.Name `xml:"hudson.tasks.Shell"`
	Command string   `xml:"command"`
}

type JobSettings struct {
	Class      string `xml:"class,attr"`
	JobSetting []JobSetting
}

type JobSetting struct {
}
type JobProperties struct {
}
type Triggers struct {
	Trigger []Trigger
}
type Trigger interface {
}
type ScmTrigger struct {
	XMLName               struct{} `xml:"hudson.triggers.SCMTrigger"`
	Spec                  string   `xml:"spec"`
	IgnorePostCommitHooks string   `xml:"ignorePostCommitHooks"`
}
type RunPostStepsIfResult struct {
	Name          string `xml:"name"`
	Ordinal       string `xml:"ordinal"`
	Color         string `xml:"color"`
	CompleteBuild string `xml:"completeBuild"`
}

type ScmGit struct {
	UserRemoteConfigs                 UserRemoteConfigs `xml:"userRemoteConfigs"`
	Branches                          Branches          `xml:"branches"`
	DoGenerateSubmoduleConfigurations bool              `xml:"doGenerateSubmoduleConfigurations"`
	GitBrowser                        GitBrowser        `xml:"browser"`
	GitSubmoduleCfg                   GitSubmoduleCfg   `xml:"submoduleCfg"`
	GitExtensions                     GitExtensions     `xml:"extensions"`
}

type UserRemoteConfigs struct {
	UserRemoteConfig UserRemoteConfig `xml:"hudson.plugins.git.UserRemoteConfig"`
}

type UserRemoteConfig struct {
	Urls []string `xml:"url"`
}

type Branches struct {
	BranchesSpec []BranchesSpec `xml:"hudson.plugins.git.BranchSpec"`
}

type BranchesSpec struct {
	Name string `xml:"name"`
}

type GitBrowser struct {
	Class       string `xml:"class,attr"`
	Url         string `xml:"url"`
	ProjectName string `xml:"projectName"`
}

type GitSubmoduleCfg struct {
	Class string `xml:"class,attr"`
}

type GitExtensions struct {
	Class       string      `xml:"class,attr"`
	LocalBranch LocalBranch `xml:"hudson.plugins.git.extensions.impl.LocalBranch"`
}

type LocalBranch struct {
	LocalBranch string `xml:"localBranch"`
}

//UnmarshalXML implements xml.UnmarshalXML intrface
//Decode between multiple types of Scm. for now only SVN is supported
func (iscm *Scm) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
	for _, v := range start.Attr {
		if v.Name.Local == "class" {
			iscm.Class = v.Value
		} else if v.Name.Local == "plugin" {
			iscm.Plugin = v.Value
		}
	}
	switch iscm.Class {
	case "hudson.scm.SubversionSCM":
		iscm.ScmContent = &ScmSvn{}
		err := d.DecodeElement(&iscm.ScmContent, &start)
		if err != nil {
			return err
		}
	case "hudson.plugins.git.GitSCM":
		iscm.ScmContent = &ScmGit{}
		err := d.DecodeElement(&iscm.ScmContent, &start)
		if err != nil {
			return err
		}
	}
	return nil
}
<commit_msg>Parse parameters in a Job (#48)<commit_after>package gojenkins

import "encoding/xml"

type Artifact struct {
	DisplayPath  string `json:"displayPath"`
	FileName     string `json:"fileName"`
	RelativePath string `json:"relativePath"`
}

type ScmAuthor struct {
	FullName    string `json:"fullName"`
	AbsoluteUrl string `json:"absoluteUrl"`
}

type ScmChangeSetPath struct {
	EditType string `json:"editType"`
	File     string `json:"File"`
}

type ChangeSetItem struct {
	AffectedPaths []string           `json:"affectedPaths"`
	CommitId      string             `json:"commitId"`
	Timestamp     int                `json:"timestamp"`
	Author        ScmAuthor          `json:"author"`
	Comment       string             `json:"comment"`
	Date          string             `json:"date"`
	Id            string             `json:"id"`
	Message       string             `json:"msg"`
	Paths         []ScmChangeSetPath `json:"paths"`
}

type ScmChangeSet struct {
	Kind  string          `json:"kind"`
	Items []ChangeSetItem `json:"items"`
}

type Build struct {
	Id     string `json:"id"`
	Number int    `json:"number"`
	Url    string `json:"url"`

	FullDisplayName string `json:"fullDisplayName"`
	Description     string `json:"description"`

	Timestamp         int `json:"timestamp"`
	Duration          int `json:"duration"`
	EstimatedDuration int `json:"estimatedDuration"`

	Building bool   `json:"building"`
	KeepLog  bool   `json:"keepLog"`
	Result   string `json:"result"`

	Artifacts []Artifact `json:"artifacts"`
	Actions   []Action   `json:"actions"`

	ChangeSet ScmChangeSet `json:"changeSet"`
}

type UpstreamCause struct {
	ShortDescription string `json:"shortDescription"`
	UpstreamBuild    int    `json:"upstreamBuild"`
	UpstreamProject  string `json:"upstreamProject"`
	UpstreamUrl      string `json:"upstreamUrl"`
}

type Job struct {
	Actions []Action `json:"actions"`
	Name    string   `json:"name"`
	Url     string   `json:"url"`
	Color   string   `json:"color"`

	Buildable    bool     `json:"buildable"`
	DisplayName  string   `json:"displayName"`
	Description  string   `json:"description"`
	HealthReport []Health `json:"healthReport"`

	LastCompletedBuild    Build `json:"lastCompletedBuild"`
	LastFailedBuild       Build `json:"lastFailedBuild"`
	LastStableBuild       Build `json:"lastStableBuild"`
	LastSuccessfulBuild   Build `json:"lastSuccessfulBuild"`
	LastUnstableBuild     Build `json:"lastUnstableBuild"`
	LastUnsuccessfulBuild Build `json:"lastUnsuccessfulBuild"`

	Property []Property `json:"property"`
}

type Health struct {
	Description string `json:"description"`
}

type Property struct {
	Parameters []JobParameter `json:"parameterDefinitions"`
}

type JobParameter struct {
	Default     Parameter `json:"defaultParameterValue"`
	Name        string    `json:"name"`
	Description string    `json:"description"`
	Type        string    `json:"type"`
	Choices     []string  `json:"choices"`
}

type MavenJobItem struct {
	XMLName                          struct{}             `xml:"maven2-moduleset"`
	Plugin                           string               `xml:"plugin,attr"`
	Actions                          string               `xml:"actions"`
	Description                      string               `xml:"description"`
	KeepDependencies                 string               `xml:"keepDependencies"`
	Properties                       JobProperties        `xml:"properties"`
	Scm                              Scm                  `xml:"scm"`
	CanRoam                          string               `xml:"canRoam"`
	Disabled                         string               `xml:"disabled"`
	BlockBuildWhenDownstreamBuilding string               `xml:"blockBuildWhenDownstreamBuilding"`
	BlockBuildWhenUpstreamBuilding   string               `xml:"blockBuildWhenUpstreamBuilding"`
	Triggers                         Triggers             `xml:"triggers"`
	ConcurrentBuild                  string               `xml:"concurrentBuild"`
	Goals                            string               `xml:"goals"`
	AggregatorStyleBuild             string               `xml:"aggregatorStyleBuild"`
	IncrementalBuild                 string               `xml:"incrementalBuild"`
	IgnoreUpstremChanges             string               `xml:"ignoreUpstremChanges"`
	ArchivingDisabled                string               `xml:"archivingDisabled"`
	SiteArchivingDisabled            string               `xml:"siteArchivingDisabled"`
	FingerprintingDisabled           string               `xml:"fingerprintingDisabled"`
	ResolveDependencies              string               `xml:"resolveDependencies"`
	ProcessPlugins                   string               `xml:"processPlugins"`
	MavenName                        string               `xml:"mavenName"`
	MavenValidationLevel             string               `xml:"mavenValidationLevel"`
	DefaultGoals                     string               `xml:"defaultGoals"`
	RunHeadless                      string               `xml:"runHeadless"`
	DisableTriggerDownstreamProjects string               `xml:"disableTriggerDownstreamProjects"`
	Settings                         JobSettings          `xml:"settings"`
	GlobalSettings                   JobSettings          `xml:"globalSettings"`
	RunPostStepsIfResult             RunPostStepsIfResult `xml:"runPostStepsIfResult"`
	Postbuilders                     PostBuilders         `xml:"postbuilders"`
}

type Scm struct {
	ScmContent
	Class  string `xml:"class,attr"`
	Plugin string `xml:"plugin,attr"`
}

type ScmContent interface{}

type ScmSvn struct {
	Locations              Locations        `xml:"locations"`
	ExcludedRegions        string           `xml:"excludedRegions"`
	IncludedRegions        string           `xml:"includedRegions"`
	ExcludedUsers          string           `xml:"excludedUsers"`
	ExcludedRevprop        string           `xml:"excludedRevprop"`
	ExcludedCommitMessages string           `xml:"excludedCommitMessages"`
	WorkspaceUpdater       WorkspaceUpdater `xml:"workspaceUpdater"`
	IgnoreDirPropChanges   string           `xml:"ignoreDirPropChanges"`
	FilterChangelog        string           `xml:"filterChangelog"`
}

type WorkspaceUpdater struct {
	Class string `xml:"class,attr"`
}
type Locations struct {
	Location []ScmSvnLocation `xml:"hudson.scm.SubversionSCM_-ModuleLocation"`
}

type ScmSvnLocation struct {
	Remote                string `xml:"remote"`
	Local                 string `xml:"local"`
	DepthOption           string `xml:"depthOption"`
	IgnoreExternalsOption string `xml:"ignoreExternalsOption"`
}

type PostBuilders struct {
	XMLName     xml.Name `xml:"postbuilders"`
	PostBuilder []PostBuilder
}

type PostBuilder interface {
}

type ShellBuilder struct {
	XMLName xml.Name `xml:"hudson.tasks.Shell"`
	Command string   `xml:"command"`
}

type JobSettings struct {
	Class      string `xml:"class,attr"`
	JobSetting []JobSetting
}

type JobSetting struct {
}
type JobProperties struct {
}
type Triggers struct {
	Trigger []Trigger
}
type Trigger interface {
}
type ScmTrigger struct {
	XMLName               struct{} `xml:"hudson.triggers.SCMTrigger"`
	Spec                  string   `xml:"spec"`
	IgnorePostCommitHooks string   `xml:"ignorePostCommitHooks"`
}
type RunPostStepsIfResult struct {
	Name          string `xml:"name"`
	Ordinal       string `xml:"ordinal"`
	Color         string `xml:"color"`
	CompleteBuild string `xml:"completeBuild"`
}

type ScmGit struct {
	UserRemoteConfigs                 UserRemoteConfigs `xml:"userRemoteConfigs"`
	Branches                          Branches          `xml:"branches"`
	DoGenerateSubmoduleConfigurations bool              `xml:"doGenerateSubmoduleConfigurations"`
	GitBrowser                        GitBrowser        `xml:"browser"`
	GitSubmoduleCfg                   GitSubmoduleCfg   `xml:"submoduleCfg"`
	GitExtensions                     GitExtensions     `xml:"extensions"`
}

type UserRemoteConfigs struct {
	UserRemoteConfig UserRemoteConfig `xml:"hudson.plugins.git.UserRemoteConfig"`
}

type UserRemoteConfig struct {
	Urls []string `xml:"url"`
}

type Branches struct {
	BranchesSpec []BranchesSpec `xml:"hudson.plugins.git.BranchSpec"`
}

type BranchesSpec struct {
	Name string `xml:"name"`
}

type GitBrowser struct {
	Class       string `xml:"class,attr"`
	Url         string `xml:"url"`
	ProjectName string `xml:"projectName"`
}

type GitSubmoduleCfg struct {
	Class string `xml:"class,attr"`
}

type GitExtensions struct {
	Class       string      `xml:"class,attr"`
	LocalBranch LocalBranch `xml:"hudson.plugins.git.extensions.impl.LocalBranch"`
}

type LocalBranch struct {
	LocalBranch string `xml:"localBranch"`
}

//UnmarshalXML implements xml.UnmarshalXML intrface
//Decode between multiple types of Scm. for now only SVN is supported
func (iscm *Scm) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
	for _, v := range start.Attr {
		if v.Name.Local == "class" {
			iscm.Class = v.Value
		} else if v.Name.Local == "plugin" {
			iscm.Plugin = v.Value
		}
	}
	switch iscm.Class {
	case "hudson.scm.SubversionSCM":
		iscm.ScmContent = &ScmSvn{}
		err := d.DecodeElement(&iscm.ScmContent, &start)
		if err != nil {
			return err
		}
	case "hudson.plugins.git.GitSCM":
		iscm.ScmContent = &ScmGit{}
		err := d.DecodeElement(&iscm.ScmContent, &start)
		if err != nil {
			return err
		}
	}
	return nil
}
<|endoftext|>


<commit_before>/*-
 * Copyright 2014 Square 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 jose

import (
	"encoding/json"
	"fmt"
	"strings"
)

// rawJsonWebEncryption represents a raw JWE JSON object. Used for parsing/serializing.
type rawJsonWebEncryption struct {
	Protected    *byteBuffer        `json:"protected,omitempty"`
	Unprotected  *rawHeader         `json:"unprotected,omitempty"`
	Header       *rawHeader         `json:"header,omitempty"`
	Recipients   []rawRecipientInfo `json:"recipients,omitempty"`
	Aad          *byteBuffer        `json:"aad,omitempty"`
	EncryptedKey *byteBuffer        `json:"encrypted_key,omitempty"`
	Iv           *byteBuffer        `json:"iv,omitempty"`
	Ciphertext   *byteBuffer        `json:"ciphertext,omitempty"`
	Tag          *byteBuffer        `json:"tag,omitempty"`
}

// rawRecipientInfo represents a raw JWE Per-Recipient header JSON object. Used for parsing/serializing.
type rawRecipientInfo struct {
	Header       *rawHeader `json:"header,omitempty"`
	EncryptedKey string     `json:"encrypted_key,omitempty"`
}

// JsonWebEncryption represents an encrypted JWE object after parsing.
type JsonWebEncryption struct {
	Header                   JoseHeader
	protected, unprotected   *rawHeader
	recipients               []recipientInfo
	aad, iv, ciphertext, tag []byte
	original                 *rawJsonWebEncryption
}

// recipientInfo represents a raw JWE Per-Recipient header JSON object after parsing.
type recipientInfo struct {
	header       *rawHeader
	encryptedKey []byte
}

// GetAuthData retrieves the (optional) authenticated data attached to the object.
func (obj JsonWebEncryption) GetAuthData() []byte {
	if obj.aad != nil {
		out := make([]byte, len(obj.aad))
		copy(out, obj.aad)
		return out
	}

	return nil
}

// Get the merged header values
func (obj JsonWebEncryption) mergedHeaders(recipient *recipientInfo) rawHeader {
	out := rawHeader{}
	out.merge(obj.protected)
	out.merge(obj.unprotected)

	if recipient != nil {
		out.merge(recipient.header)
	}

	return out
}

// Get the additional authenticated data from a JWE object.
func (obj JsonWebEncryption) computeAuthData() []byte {
	var protected string

	if obj.original != nil {
		protected = obj.original.Protected.base64()
	} else {
		protected = base64URLEncode(mustSerializeJSON((obj.protected)))
	}

	output := []byte(protected)
	if obj.aad != nil {
		output = append(output, '.')
		output = append(output, []byte(base64URLEncode(obj.aad))...)
	}

	return output
}

// ParseEncrypted parses an encrypted message in compact or full serialization format.
func ParseEncrypted(input string) (*JsonWebEncryption, error) {
	input = stripWhitespace(input)
	if strings.HasPrefix(input, "{") {
		return parseEncryptedFull(input)
	}

	return parseEncryptedCompact(input)
}

// parseEncryptedFull parses a message in compact format.
func parseEncryptedFull(input string) (*JsonWebEncryption, error) {
	var parsed rawJsonWebEncryption
	err := json.Unmarshal([]byte(input), &parsed)
	if err != nil {
		return nil, err
	}

	return parsed.sanitized()
}

// sanitized produces a cleaned-up JWE object from the raw JSON.
func (parsed *rawJsonWebEncryption) sanitized() (*JsonWebEncryption, error) {
	obj := &JsonWebEncryption{
		original:    parsed,
		unprotected: parsed.Unprotected,
	}

	obj.Header = obj.mergedHeaders(nil).sanitized()

	if parsed.Protected != nil && len(parsed.Protected.bytes()) > 0 {
		err := json.Unmarshal(parsed.Protected.bytes(), &obj.protected)
		if err != nil {
			return nil, fmt.Errorf("square/go-jose: invalid protected header: %s, %s", err, parsed.Protected.base64())
		}
	}

	if len(parsed.Recipients) == 0 {
		obj.recipients = []recipientInfo{
			recipientInfo{
				header:       parsed.Header,
				encryptedKey: parsed.EncryptedKey.bytes(),
			},
		}
	} else {
		obj.recipients = make([]recipientInfo, len(parsed.Recipients))
		for r := range parsed.Recipients {
			encryptedKey, err := base64URLDecode(parsed.Recipients[r].EncryptedKey)
			if err != nil {
				return nil, err
			}

			obj.recipients[r].header = parsed.Recipients[r].Header
			obj.recipients[r].encryptedKey = encryptedKey
		}
	}

	for _, recipient := range obj.recipients {
		headers := obj.mergedHeaders(&recipient)
		if headers.Alg == "" || headers.Enc == "" {
			return nil, fmt.Errorf("square/go-jose: message is missing alg/enc headers")
		}
	}

	obj.iv = parsed.Iv.bytes()
	obj.ciphertext = parsed.Ciphertext.bytes()
	obj.tag = parsed.Tag.bytes()
	obj.aad = parsed.Aad.bytes()

	return obj, nil
}

// parseEncryptedCompact parses a message in compact format.
func parseEncryptedCompact(input string) (*JsonWebEncryption, error) {
	parts := strings.Split(input, ".")
	if len(parts) != 5 {
		return nil, fmt.Errorf("square/go-jose: compact JWE format must have five parts")
	}

	rawProtected, err := base64URLDecode(parts[0])
	if err != nil {
		return nil, err
	}

	encryptedKey, err := base64URLDecode(parts[1])
	if err != nil {
		return nil, err
	}

	iv, err := base64URLDecode(parts[2])
	if err != nil {
		return nil, err
	}

	ciphertext, err := base64URLDecode(parts[3])
	if err != nil {
		return nil, err
	}

	tag, err := base64URLDecode(parts[4])
	if err != nil {
		return nil, err
	}

	raw := &rawJsonWebEncryption{
		Protected:    newBuffer(rawProtected),
		EncryptedKey: newBuffer(encryptedKey),
		Iv:           newBuffer(iv),
		Ciphertext:   newBuffer(ciphertext),
		Tag:          newBuffer(tag),
	}

	return raw.sanitized()
}

// CompactSerialize serializes an object using the compact serialization format.
func (obj JsonWebEncryption) CompactSerialize() (string, error) {
	if len(obj.recipients) > 1 || obj.unprotected != nil || obj.recipients[0].header != nil {
		return "", ErrNotSupported
	}

	serializedProtected := mustSerializeJSON(obj.protected)

	return fmt.Sprintf(
		"%s.%s.%s.%s.%s",
		base64URLEncode(serializedProtected),
		base64URLEncode(obj.recipients[0].encryptedKey),
		base64URLEncode(obj.iv),
		base64URLEncode(obj.ciphertext),
		base64URLEncode(obj.tag)), nil
}

// FullSerialize serializes an object using the full JSON serialization format.
func (obj JsonWebEncryption) FullSerialize() string {
	raw := rawJsonWebEncryption{
		Unprotected:  obj.unprotected,
		Iv:           newBuffer(obj.iv),
		Ciphertext:   newBuffer(obj.ciphertext),
		EncryptedKey: newBuffer(obj.recipients[0].encryptedKey),
		Tag:          newBuffer(obj.tag),
		Aad:          newBuffer(obj.aad),
		Recipients:   []rawRecipientInfo{},
	}

	if len(obj.recipients) > 1 {
		for _, recipient := range obj.recipients {
			info := rawRecipientInfo{
				Header:       recipient.header,
				EncryptedKey: base64URLEncode(recipient.encryptedKey),
			}
			raw.Recipients = append(raw.Recipients, info)
		}
	} else {
		// Use flattened serialization
		raw.Header = obj.recipients[0].header
		raw.EncryptedKey = newBuffer(obj.recipients[0].encryptedKey)
	}

	raw.Protected = newBuffer(mustSerializeJSON(obj.protected))

	return string(mustSerializeJSON(raw))
}
<commit_msg>Analogous change for JWE<commit_after>/*-
 * Copyright 2014 Square 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 jose

import (
	"encoding/json"
	"fmt"
	"strings"
)

// rawJsonWebEncryption represents a raw JWE JSON object. Used for parsing/serializing.
type rawJsonWebEncryption struct {
	Protected    *byteBuffer        `json:"protected,omitempty"`
	Unprotected  *rawHeader         `json:"unprotected,omitempty"`
	Header       *rawHeader         `json:"header,omitempty"`
	Recipients   []rawRecipientInfo `json:"recipients,omitempty"`
	Aad          *byteBuffer        `json:"aad,omitempty"`
	EncryptedKey *byteBuffer        `json:"encrypted_key,omitempty"`
	Iv           *byteBuffer        `json:"iv,omitempty"`
	Ciphertext   *byteBuffer        `json:"ciphertext,omitempty"`
	Tag          *byteBuffer        `json:"tag,omitempty"`
}

// rawRecipientInfo represents a raw JWE Per-Recipient header JSON object. Used for parsing/serializing.
type rawRecipientInfo struct {
	Header       *rawHeader `json:"header,omitempty"`
	EncryptedKey string     `json:"encrypted_key,omitempty"`
}

// JsonWebEncryption represents an encrypted JWE object after parsing.
type JsonWebEncryption struct {
	Header                   JoseHeader
	protected, unprotected   *rawHeader
	recipients               []recipientInfo
	aad, iv, ciphertext, tag []byte
	original                 *rawJsonWebEncryption
}

// recipientInfo represents a raw JWE Per-Recipient header JSON object after parsing.
type recipientInfo struct {
	header       *rawHeader
	encryptedKey []byte
}

// GetAuthData retrieves the (optional) authenticated data attached to the object.
func (obj JsonWebEncryption) GetAuthData() []byte {
	if obj.aad != nil {
		out := make([]byte, len(obj.aad))
		copy(out, obj.aad)
		return out
	}

	return nil
}

// Get the merged header values
func (obj JsonWebEncryption) mergedHeaders(recipient *recipientInfo) rawHeader {
	out := rawHeader{}
	out.merge(obj.protected)
	out.merge(obj.unprotected)

	if recipient != nil {
		out.merge(recipient.header)
	}

	return out
}

// Get the additional authenticated data from a JWE object.
func (obj JsonWebEncryption) computeAuthData() []byte {
	var protected string

	if obj.original != nil {
		protected = obj.original.Protected.base64()
	} else {
		protected = base64URLEncode(mustSerializeJSON((obj.protected)))
	}

	output := []byte(protected)
	if obj.aad != nil {
		output = append(output, '.')
		output = append(output, []byte(base64URLEncode(obj.aad))...)
	}

	return output
}

// ParseEncrypted parses an encrypted message in compact or full serialization format.
func ParseEncrypted(input string) (*JsonWebEncryption, error) {
	input = stripWhitespace(input)
	if strings.HasPrefix(input, "{") {
		return parseEncryptedFull(input)
	}

	return parseEncryptedCompact(input)
}

// parseEncryptedFull parses a message in compact format.
func parseEncryptedFull(input string) (*JsonWebEncryption, error) {
	var parsed rawJsonWebEncryption
	err := json.Unmarshal([]byte(input), &parsed)
	if err != nil {
		return nil, err
	}

	return parsed.sanitized()
}

// sanitized produces a cleaned-up JWE object from the raw JSON.
func (parsed *rawJsonWebEncryption) sanitized() (*JsonWebEncryption, error) {
	obj := &JsonWebEncryption{
		original:    parsed,
		unprotected: parsed.Unprotected,
	}

	obj.Header = obj.mergedHeaders(nil).sanitized()

	if parsed.Protected != nil && len(parsed.Protected.bytes()) > 0 {
		err := json.Unmarshal(parsed.Protected.bytes(), &obj.protected)
		if err != nil {
			return nil, fmt.Errorf("square/go-jose: invalid protected header: %s, %s", err, parsed.Protected.base64())
		}
	}

	if len(parsed.Recipients) == 0 {
		obj.recipients = []recipientInfo{
			recipientInfo{
				header:       parsed.Header,
				encryptedKey: parsed.EncryptedKey.bytes(),
			},
		}
	} else {
		obj.recipients = make([]recipientInfo, len(parsed.Recipients))
		for r := range parsed.Recipients {
			encryptedKey, err := base64URLDecode(parsed.Recipients[r].EncryptedKey)
			if err != nil {
				return nil, err
			}

			obj.recipients[r].header = parsed.Recipients[r].Header
			obj.recipients[r].encryptedKey = encryptedKey
		}
	}

	for _, recipient := range obj.recipients {
		headers := obj.mergedHeaders(&recipient)
		if headers.Alg == "" || headers.Enc == "" {
			return nil, fmt.Errorf("square/go-jose: message is missing alg/enc headers")
		}
	}

	obj.iv = parsed.Iv.bytes()
	obj.ciphertext = parsed.Ciphertext.bytes()
	obj.tag = parsed.Tag.bytes()
	obj.aad = parsed.Aad.bytes()

	return obj, nil
}

// parseEncryptedCompact parses a message in compact format.
func parseEncryptedCompact(input string) (*JsonWebEncryption, error) {
	parts := strings.Split(input, ".")
	if len(parts) != 5 {
		return nil, fmt.Errorf("square/go-jose: compact JWE format must have five parts")
	}

	rawProtected, err := base64URLDecode(parts[0])
	if err != nil {
		return nil, err
	}

	encryptedKey, err := base64URLDecode(parts[1])
	if err != nil {
		return nil, err
	}

	iv, err := base64URLDecode(parts[2])
	if err != nil {
		return nil, err
	}

	ciphertext, err := base64URLDecode(parts[3])
	if err != nil {
		return nil, err
	}

	tag, err := base64URLDecode(parts[4])
	if err != nil {
		return nil, err
	}

	raw := &rawJsonWebEncryption{
		Protected:    newBuffer(rawProtected),
		EncryptedKey: newBuffer(encryptedKey),
		Iv:           newBuffer(iv),
		Ciphertext:   newBuffer(ciphertext),
		Tag:          newBuffer(tag),
	}

	return raw.sanitized()
}

// CompactSerialize serializes an object using the compact serialization format.
func (obj JsonWebEncryption) CompactSerialize() (string, error) {
	if len(obj.recipients) > 1 || obj.unprotected != nil ||
		obj.protected == nil || obj.recipients[0].header != nil {
		return "", ErrNotSupported
	}

	serializedProtected := mustSerializeJSON(obj.protected)

	return fmt.Sprintf(
		"%s.%s.%s.%s.%s",
		base64URLEncode(serializedProtected),
		base64URLEncode(obj.recipients[0].encryptedKey),
		base64URLEncode(obj.iv),
		base64URLEncode(obj.ciphertext),
		base64URLEncode(obj.tag)), nil
}

// FullSerialize serializes an object using the full JSON serialization format.
func (obj JsonWebEncryption) FullSerialize() string {
	raw := rawJsonWebEncryption{
		Unprotected:  obj.unprotected,
		Iv:           newBuffer(obj.iv),
		Ciphertext:   newBuffer(obj.ciphertext),
		EncryptedKey: newBuffer(obj.recipients[0].encryptedKey),
		Tag:          newBuffer(obj.tag),
		Aad:          newBuffer(obj.aad),
		Recipients:   []rawRecipientInfo{},
	}

	if len(obj.recipients) > 1 {
		for _, recipient := range obj.recipients {
			info := rawRecipientInfo{
				Header:       recipient.header,
				EncryptedKey: base64URLEncode(recipient.encryptedKey),
			}
			raw.Recipients = append(raw.Recipients, info)
		}
	} else {
		// Use flattened serialization
		raw.Header = obj.recipients[0].header
		raw.EncryptedKey = newBuffer(obj.recipients[0].encryptedKey)
	}

	if obj.protected != nil {
		raw.Protected = newBuffer(mustSerializeJSON(obj.protected))
	}

	return string(mustSerializeJSON(raw))
}
<|endoftext|>


<commit_before>package ari

import "fmt"

const (
	// ApplicationKey is the key kind for ARI Application resources.
	ApplicationKey = "application"

	// BridgeKey is the key kind for the ARI Bridge resources.
	BridgeKey = "bridge"

	// ChannelKey is the key kind for the ARI Channel resource
	ChannelKey = "channel"

	// DeviceStateKey is the key kind for the ARI DeviceState resource
	DeviceStateKey = "devicestate"

	// EndpointKey is the key kind for the ARI Endpoint resource
	EndpointKey = "endpoint"

	// LiveRecordingKey is the key kind for the ARI LiveRecording resource
	LiveRecordingKey = "liverecording"

	// LoggingKey is the key kind for the ARI Logging resource
	LoggingKey = "logging"

	// MailboxKey is the key kind for the ARI Mailbox resource
	MailboxKey = "mailbox"

	// ModuleKey is the key kind for the ARI Module resource
	ModuleKey = "module"

	// PlaybackKey is the key kind for the ARI Playback resource
	PlaybackKey = "playback"

	// SoundKey is the key kind for the ARI Sound resource
	SoundKey = "sound"

	// StoredRecordingKey is the key kind for the ARI StoredRecording resource
	StoredRecordingKey = "storedrecording"

	// VariableKey is the key kind for the ARI Asterisk Variable resource
	VariableKey = "variable"
)

// Key identifies a unique resource in the system
type Key struct {
	// Kind indicates the type of resource the Key points to.  e.g., "channel",
	// "bridge", etc.
	Kind string `json:"kind"`

	// ID indicates the unique identifier of the resource
	ID string `json:"id"`

	// Node indicates the unique identifier of the Asterisk node on which the
	// resource exists or will be created
	Node string `json:"node,omitempty"`

	// Dialog indicates a named scope of the resource, for receiving events
	Dialog string `json:"dialog,omitempty"`

	// App indiciates the ARI application that this key is bound to.
	App string `json:"app,omitempty"`
}

// Keys is a list of keys
type Keys []*Key

// Filter filters the key list using the given key type match
func (kx Keys) Filter(mx ...Matcher) (ret Keys) {
	for _, m := range mx {
		for _, k := range kx {
			if m.Match(k) {
				ret = append(ret, k)
			}
		}
	}
	return
}

// Without removes keys that match the given matcher
func (kx Keys) Without(m Matcher) (ret Keys) {
	for _, k := range kx {
		if !m.Match(k) {
			ret = append(ret, k)
		}
	}
	return
}

// First returns the first key from a list of keys.  It is safe to use on empty lists, in which case, it will return nil.
func (kx Keys) First() *Key {
	if len(kx) < 1 {
		return nil
	}
	return kx[0]
}

// Bridges returns just the bridge keys from a set of Keys
func (kx Keys) Bridges() Keys {
	return kx.Filter(NewKey(BridgeKey, ""))
}

// Channels returns just the channel keys from a set of Keys
func (kx Keys) Channels() Keys {
	return kx.Filter(NewKey(ChannelKey, ""))
}

// A Matcher provides the functionality for matching against a key.
type Matcher interface {
	Match(o *Key) bool
}

// MatchFunc is the functional type alias for providing functional `Matcher` implementations
type MatchFunc func(*Key) bool

// Match invokes the match function given the key
func (mf MatchFunc) Match(o *Key) bool {
	return mf(o)
}

// KeyOptionFunc is a functional argument alias for providing options for ARI keys
type KeyOptionFunc func(Key) Key

// WithDialog sets the given dialog identifier on the key.
func WithDialog(dialog string) KeyOptionFunc {
	return func(key Key) Key {
		key.Dialog = dialog
		return key
	}
}

// WithNode sets the given node identifier on the key.
func WithNode(node string) KeyOptionFunc {
	return func(key Key) Key {
		key.Node = node
		return key
	}
}

// WithApp sets the given node identifier on the key.
func WithApp(app string) KeyOptionFunc {
	return func(key Key) Key {
		key.App = app
		return key
	}
}

// WithLocationOf copies the partial key fields Node, Application, Dialog from the reference key
func WithLocationOf(ref *Key) KeyOptionFunc {
	return func(key Key) Key {
		if ref != nil {
			key.Node = ref.Node
			key.Dialog = ref.Dialog
			key.App = ref.App
		}
		return key
	}
}

// NewKey builds a new key given the kind, identifier, and any optional arguments.
func NewKey(kind string, id string, opts ...KeyOptionFunc) *Key {
	k := Key{
		Kind: kind,
		ID:   id,
	}
	for _, o := range opts {
		k = o(k)
	}

	return &k
}

// AppKey returns a key that is bound to the given application.
func AppKey(app string) *Key {
	return NewKey("", "", WithApp(app))
}

// ConfigID returns the configuration Key ID for the given configuration class, type/kind, and id.
func ConfigID(class, kind, id string) string {
	return fmt.Sprintf("%s/%s/%s", class, kind, id)
}

// EndpointID returns the endpoint Key ID for the given tech and resource
func EndpointID(tech, resource string) string {
	return fmt.Sprintf("%s/%s", tech, resource)
}

// DialogKey returns a key that is bound to the given dialog.
func DialogKey(dialog string) *Key {
	return NewKey("", "", WithDialog(dialog))
}

// NodeKey returns a key that is bound to the given application and node
func NodeKey(app, node string) *Key {
	return NewKey("", "", WithApp(app), WithNode(node))
}

// KindKey returns a key that is bound by a type only
func KindKey(kind string, opts ...KeyOptionFunc) *Key {
	return NewKey(kind, "", opts...)
}

// Match returns true if the given key matches the subject. Empty partial key fields are wildcards.
func (k *Key) Match(o *Key) bool {
	if k == o {
		return true
	}

	if k == nil || o == nil {
		return false
	}

	if k.App != "" && o.App != "" && k.App != o.App {
		return false
	}
	if k.Dialog != "" && o.Dialog != "" && k.Dialog != o.Dialog {
		return false
	}
	if k.Node != "" && o.Node != "" && k.Node != o.Node {
		return false
	}
	if k.Kind != "" && o.Kind != "" && k.Kind != o.Kind {
		return false
	}
	if k.ID != "" && o.ID != "" && k.ID != o.ID {
		return false
	}

	return true
}

// New returns a new key with the location information from the source key.
// This includes the App, the Node, and the Dialog.  the `kind` and `id`
// parameters are optional.  If kind is empty, the resulting key will not be
// typed.  If id is empty, the key will not be unique.
func (k *Key) New(kind, id string) *Key {
	n := NodeKey(k.App, k.Node)
	n.Dialog = k.Dialog
	n.Kind = kind
	n.ID = id

	return n
}

func (k *Key) String() string {
	if k.ID != "" {
		return k.ID
	}

	if k.Dialog != "" {
		return "[" + k.Dialog + "]"
	}

	if k.Node != "" {
		return k.App + "@" + k.Node
	}

	return "emptyKey"
}
<commit_msg>add keys.ID()<commit_after>package ari

import "fmt"

const (
	// ApplicationKey is the key kind for ARI Application resources.
	ApplicationKey = "application"

	// BridgeKey is the key kind for the ARI Bridge resources.
	BridgeKey = "bridge"

	// ChannelKey is the key kind for the ARI Channel resource
	ChannelKey = "channel"

	// DeviceStateKey is the key kind for the ARI DeviceState resource
	DeviceStateKey = "devicestate"

	// EndpointKey is the key kind for the ARI Endpoint resource
	EndpointKey = "endpoint"

	// LiveRecordingKey is the key kind for the ARI LiveRecording resource
	LiveRecordingKey = "liverecording"

	// LoggingKey is the key kind for the ARI Logging resource
	LoggingKey = "logging"

	// MailboxKey is the key kind for the ARI Mailbox resource
	MailboxKey = "mailbox"

	// ModuleKey is the key kind for the ARI Module resource
	ModuleKey = "module"

	// PlaybackKey is the key kind for the ARI Playback resource
	PlaybackKey = "playback"

	// SoundKey is the key kind for the ARI Sound resource
	SoundKey = "sound"

	// StoredRecordingKey is the key kind for the ARI StoredRecording resource
	StoredRecordingKey = "storedrecording"

	// VariableKey is the key kind for the ARI Asterisk Variable resource
	VariableKey = "variable"
)

// Key identifies a unique resource in the system
type Key struct {
	// Kind indicates the type of resource the Key points to.  e.g., "channel",
	// "bridge", etc.
	Kind string `json:"kind"`

	// ID indicates the unique identifier of the resource
	ID string `json:"id"`

	// Node indicates the unique identifier of the Asterisk node on which the
	// resource exists or will be created
	Node string `json:"node,omitempty"`

	// Dialog indicates a named scope of the resource, for receiving events
	Dialog string `json:"dialog,omitempty"`

	// App indiciates the ARI application that this key is bound to.
	App string `json:"app,omitempty"`
}

// Keys is a list of keys
type Keys []*Key

// Filter filters the key list using the given key type match
func (kx Keys) Filter(mx ...Matcher) (ret Keys) {
	for _, m := range mx {
		for _, k := range kx {
			if m.Match(k) {
				ret = append(ret, k)
			}
		}
	}
	return
}

// Without removes keys that match the given matcher
func (kx Keys) Without(m Matcher) (ret Keys) {
	for _, k := range kx {
		if !m.Match(k) {
			ret = append(ret, k)
		}
	}
	return
}

// First returns the first key from a list of keys.  It is safe to use on empty lists, in which case, it will return nil.
func (kx Keys) First() *Key {
	if len(kx) < 1 {
		return nil
	}
	return kx[0]
}

// Bridges returns just the bridge keys from a set of Keys
func (kx Keys) Bridges() Keys {
	return kx.Filter(NewKey(BridgeKey, ""))
}

// Channels returns just the channel keys from a set of Keys
func (kx Keys) Channels() Keys {
	return kx.Filter(NewKey(ChannelKey, ""))
}

// ID returns the key from a set of keys with ID matching the given ID.  If the
// key does not exist in the set, nil is returned.
func (kx Keys) ID(id string) *Key {
	return kx.Filter(NewKey("", id)).First()
}

// A Matcher provides the functionality for matching against a key.
type Matcher interface {
	Match(o *Key) bool
}

// MatchFunc is the functional type alias for providing functional `Matcher` implementations
type MatchFunc func(*Key) bool

// Match invokes the match function given the key
func (mf MatchFunc) Match(o *Key) bool {
	return mf(o)
}

// KeyOptionFunc is a functional argument alias for providing options for ARI keys
type KeyOptionFunc func(Key) Key

// WithDialog sets the given dialog identifier on the key.
func WithDialog(dialog string) KeyOptionFunc {
	return func(key Key) Key {
		key.Dialog = dialog
		return key
	}
}

// WithNode sets the given node identifier on the key.
func WithNode(node string) KeyOptionFunc {
	return func(key Key) Key {
		key.Node = node
		return key
	}
}

// WithApp sets the given node identifier on the key.
func WithApp(app string) KeyOptionFunc {
	return func(key Key) Key {
		key.App = app
		return key
	}
}

// WithLocationOf copies the partial key fields Node, Application, Dialog from the reference key
func WithLocationOf(ref *Key) KeyOptionFunc {
	return func(key Key) Key {
		if ref != nil {
			key.Node = ref.Node
			key.Dialog = ref.Dialog
			key.App = ref.App
		}
		return key
	}
}

// NewKey builds a new key given the kind, identifier, and any optional arguments.
func NewKey(kind string, id string, opts ...KeyOptionFunc) *Key {
	k := Key{
		Kind: kind,
		ID:   id,
	}
	for _, o := range opts {
		k = o(k)
	}

	return &k
}

// AppKey returns a key that is bound to the given application.
func AppKey(app string) *Key {
	return NewKey("", "", WithApp(app))
}

// ConfigID returns the configuration Key ID for the given configuration class, type/kind, and id.
func ConfigID(class, kind, id string) string {
	return fmt.Sprintf("%s/%s/%s", class, kind, id)
}

// EndpointID returns the endpoint Key ID for the given tech and resource
func EndpointID(tech, resource string) string {
	return fmt.Sprintf("%s/%s", tech, resource)
}

// DialogKey returns a key that is bound to the given dialog.
func DialogKey(dialog string) *Key {
	return NewKey("", "", WithDialog(dialog))
}

// NodeKey returns a key that is bound to the given application and node
func NodeKey(app, node string) *Key {
	return NewKey("", "", WithApp(app), WithNode(node))
}

// KindKey returns a key that is bound by a type only
func KindKey(kind string, opts ...KeyOptionFunc) *Key {
	return NewKey(kind, "", opts...)
}

// Match returns true if the given key matches the subject. Empty partial key fields are wildcards.
func (k *Key) Match(o *Key) bool {
	if k == o {
		return true
	}

	if k == nil || o == nil {
		return false
	}

	if k.App != "" && o.App != "" && k.App != o.App {
		return false
	}
	if k.Dialog != "" && o.Dialog != "" && k.Dialog != o.Dialog {
		return false
	}
	if k.Node != "" && o.Node != "" && k.Node != o.Node {
		return false
	}
	if k.Kind != "" && o.Kind != "" && k.Kind != o.Kind {
		return false
	}
	if k.ID != "" && o.ID != "" && k.ID != o.ID {
		return false
	}

	return true
}

// New returns a new key with the location information from the source key.
// This includes the App, the Node, and the Dialog.  the `kind` and `id`
// parameters are optional.  If kind is empty, the resulting key will not be
// typed.  If id is empty, the key will not be unique.
func (k *Key) New(kind, id string) *Key {
	n := NodeKey(k.App, k.Node)
	n.Dialog = k.Dialog
	n.Kind = kind
	n.ID = id

	return n
}

func (k *Key) String() string {
	if k.ID != "" {
		return k.ID
	}

	if k.Dialog != "" {
		return "[" + k.Dialog + "]"
	}

	if k.Node != "" {
		return k.App + "@" + k.Node
	}

	return "emptyKey"
}
<|endoftext|>


<commit_before>package log

import (
	"encoding/json"
	"fmt"
	"net/http"
	"os"
	"path/filepath"
	"runtime"
	"sync"
	"time"
)

type (
	MsgType uint8
	OutType uint8
)

const (
	MessageLog         MsgType = 0
	Message2Log        MsgType = 1
	WarningLog         MsgType = 2
	DebugLog           MsgType = 3
	ErrorLog           MsgType = 4
	FormattedOut       OutType = 0
	LineOut            OutType = 1
	DefaultMaxLineSize int     = 2000
	DefaultTimeFormat  string  = "2006/01/02 15:04:05"
)

// AdapterFunc is the type for the function adapter
// any function that has this signature can be used as an adapter
type AdapterFunc func(m MsgType, o OutType, config map[string]interface{}, msg ...interface{})

// AdapterPod contains the metadata of an adapter
type AdapterPod struct {
	Adapter AdapterFunc
	Config  map[string]interface{}
}

var (
	// DebugMode Enable debug mode
	DebugMode bool

	// EnableANSIColors enables ANSI colors, default true
	EnableANSIColors = true

	// MaxLineSize limits the size of the line, if the size
	// exceeds that indicated by MaxLineSize the system cuts
	// the string and adds "..." at the end.
	MaxLineSize = DefaultMaxLineSize

	// TimeFormat defines which pattern will be applied for
	// display time in the logs.
	TimeFormat = DefaultTimeFormat

	// Colors contain color array
	Colors = []string{
		MessageLog:  "\x1b[37m", // White
		Message2Log: "\x1b[92m", // Light green
		WarningLog:  "\x1b[93m", // Light Yellow
		DebugLog:    "\x1b[96m", // Light Cyan
		ErrorLog:    "\x1b[91m", // Light Red
	}

	// Prefixes of messages
	Prefixes = []string{
		MessageLog:  "msg",
		Message2Log: "msg",
		WarningLog:  "warning",
		DebugLog:    "debug",
		ErrorLog:    "error",
	}

	now      = time.Now
	adapters = make(map[string]AdapterPod)
	lock     = sync.RWMutex{}
)

func init() {
	if len(adapters) == 0 {
		AddAdapter("stdout", AdapterPod{
			Adapter: pln,
			Config:  nil,
		})
	}
}

// AddAdapter allows to add an adapter and parameters
func AddAdapter(name string, adapter AdapterPod) {
	lock.Lock()
	adapters[name] = adapter
	lock.Unlock()
}

// RemoveAdapter remove the adapter from list
func RemoveAdapter(name string) {
	lock.Lock()
	delete(adapters, name)
	lock.Unlock()
}

// SetAdapterConfig allows set new adapter parameters
func SetAdapterConfig(name string, config map[string]interface{}) {
	lock.Lock()
	a := adapters[name]
	a.Config = config
	adapters[name] = a
	lock.Unlock()
}

func runAdapters(m MsgType, o OutType, msg ...interface{}) {
	lock.RLock()
	defer lock.RUnlock()
	for _, a := range adapters {
		a.Adapter(m, o, a.Config, msg...)
	}
}

// HTTPError write lot to stdout and return json error on http.ResponseWriter with http error code.
func HTTPError(w http.ResponseWriter, code int) {
	msg := http.StatusText(code)
	Errorln(msg)
	m := make(map[string]string)
	m["status"] = "error"
	m["error"] = msg
	b, _ := json.MarshalIndent(m, "", "\t")
	http.Error(w, string(b), code)
}

// Fatal show message with line break at the end and exit to OS.
func Fatal(msg ...interface{}) {
	runAdapters(ErrorLog, LineOut, msg...)
	os.Exit(-1)
}

// Errorln message with line break at the end.
func Errorln(msg ...interface{}) {
	runAdapters(ErrorLog, LineOut, msg...)
}

// Errorf shows formatted error message on stdout without line break at the end.
func Errorf(msg ...interface{}) {
	runAdapters(ErrorLog, FormattedOut, msg...)
}

// Warningln shows warning message on stdout with line break at the end.
func Warningln(msg ...interface{}) {
	runAdapters(WarningLog, LineOut, msg...)
}

// Warningf shows formatted warning message on stdout without line break at the end.
func Warningf(msg ...interface{}) {
	runAdapters(WarningLog, FormattedOut, msg...)
}

// Println shows message on stdout with line break at the end.
func Println(msg ...interface{}) {
	runAdapters(MessageLog, LineOut, msg...)
}

// Printf shows formatted message on stdout without line break at the end.
func Printf(msg ...interface{}) {
	runAdapters(MessageLog, FormattedOut, msg...)
}

// Debugln shows debug message on stdout with line break at the end.
// If debug mode is not active no message is displayed
func Debugln(msg ...interface{}) {
	runAdapters(DebugLog, LineOut, msg...)
}

// Debugf shows debug message on stdout without line break at the end.
// If debug mode is not active no message is displayed
func Debugf(msg ...interface{}) {
	runAdapters(DebugLog, FormattedOut, msg...)
}

func pln(m MsgType, o OutType, config map[string]interface{}, msg ...interface{}) {
	if m == DebugLog && !DebugMode {
		return
	}

	var debugInfo, lineBreak, output string

	if DebugMode {
		_, fn, line, _ := runtime.Caller(5)
		fn = filepath.Base(fn)
		debugInfo = fmt.Sprintf("%s:%d ", fn, line)
	}

	if o == FormattedOut {
		output = fmt.Sprintf(msg[0].(string), msg[1:]...)
	} else {
		output = fmt.Sprint(msg...)
		lineBreak = "\n"
	}

	if EnableANSIColors {
		output = fmt.Sprintf("%s%s [%s] %s%s\033[0;00m",
			Colors[m],
			now().Format(TimeFormat),
			Prefixes[m],
			debugInfo,
			output)
	} else {
		output = fmt.Sprintf("%s [%s] %s%s",
			now().Format(TimeFormat),
			Prefixes[m],
			debugInfo,
			output)
	}

	if len(output) > MaxLineSize {
		output = output[:MaxLineSize] + "..."
	}
	output = output + lineBreak
	fmt.Print(output)
}
<commit_msg>log: export default adapter (#28)<commit_after>package log

import (
	"encoding/json"
	"fmt"
	"net/http"
	"os"
	"path/filepath"
	"runtime"
	"sync"
	"time"
)

type (
	MsgType uint8
	OutType uint8
)

const (
	MessageLog         MsgType = 0
	Message2Log        MsgType = 1
	WarningLog         MsgType = 2
	DebugLog           MsgType = 3
	ErrorLog           MsgType = 4
	FormattedOut       OutType = 0
	LineOut            OutType = 1
	DefaultMaxLineSize int     = 2000
	DefaultTimeFormat  string  = "2006/01/02 15:04:05"
)

// AdapterFunc is the type for the function adapter
// any function that has this signature can be used as an adapter
type AdapterFunc func(m MsgType, o OutType, config map[string]interface{}, msg ...interface{})

// AdapterPod contains the metadata of an adapter
type AdapterPod struct {
	Adapter AdapterFunc
	Config  map[string]interface{}
}

var (
	// DebugMode Enable debug mode
	DebugMode bool

	// EnableANSIColors enables ANSI colors, default true
	EnableANSIColors = true

	// MaxLineSize limits the size of the line, if the size
	// exceeds that indicated by MaxLineSize the system cuts
	// the string and adds "..." at the end.
	MaxLineSize = DefaultMaxLineSize

	// TimeFormat defines which pattern will be applied for
	// display time in the logs.
	TimeFormat = DefaultTimeFormat

	// Colors contain color array
	Colors = []string{
		MessageLog:  "\x1b[37m", // White
		Message2Log: "\x1b[92m", // Light green
		WarningLog:  "\x1b[93m", // Light Yellow
		DebugLog:    "\x1b[96m", // Light Cyan
		ErrorLog:    "\x1b[91m", // Light Red
	}

	// Prefixes of messages
	Prefixes = []string{
		MessageLog:  "msg",
		Message2Log: "msg",
		WarningLog:  "warning",
		DebugLog:    "debug",
		ErrorLog:    "error",
	}

	now      = time.Now
	adapters = make(map[string]AdapterPod)
	lock     = sync.RWMutex{}
)

func init() {
	if len(adapters) == 0 {
		AddAdapter("stdout", AdapterPod{
			Adapter: DefaultAdapter,
			Config:  nil,
		})
	}
}

// AddAdapter allows to add an adapter and parameters
func AddAdapter(name string, adapter AdapterPod) {
	lock.Lock()
	adapters[name] = adapter
	lock.Unlock()
}

// RemoveAdapter remove the adapter from list
func RemoveAdapter(name string) {
	lock.Lock()
	delete(adapters, name)
	lock.Unlock()
}

// SetAdapterConfig allows set new adapter parameters
func SetAdapterConfig(name string, config map[string]interface{}) {
	lock.Lock()
	a := adapters[name]
	a.Config = config
	adapters[name] = a
	lock.Unlock()
}

func runAdapters(m MsgType, o OutType, msg ...interface{}) {
	lock.RLock()
	defer lock.RUnlock()
	for _, a := range adapters {
		a.Adapter(m, o, a.Config, msg...)
	}
}

// HTTPError write lot to stdout and return json error on http.ResponseWriter with http error code.
func HTTPError(w http.ResponseWriter, code int) {
	msg := http.StatusText(code)
	Errorln(msg)
	m := make(map[string]string)
	m["status"] = "error"
	m["error"] = msg
	b, _ := json.MarshalIndent(m, "", "\t")
	http.Error(w, string(b), code)
}

// Fatal show message with line break at the end and exit to OS.
func Fatal(msg ...interface{}) {
	runAdapters(ErrorLog, LineOut, msg...)
	os.Exit(-1)
}

// Errorln message with line break at the end.
func Errorln(msg ...interface{}) {
	runAdapters(ErrorLog, LineOut, msg...)
}

// Errorf shows formatted error message on stdout without line break at the end.
func Errorf(msg ...interface{}) {
	runAdapters(ErrorLog, FormattedOut, msg...)
}

// Warningln shows warning message on stdout with line break at the end.
func Warningln(msg ...interface{}) {
	runAdapters(WarningLog, LineOut, msg...)
}

// Warningf shows formatted warning message on stdout without line break at the end.
func Warningf(msg ...interface{}) {
	runAdapters(WarningLog, FormattedOut, msg...)
}

// Println shows message on stdout with line break at the end.
func Println(msg ...interface{}) {
	runAdapters(MessageLog, LineOut, msg...)
}

// Printf shows formatted message on stdout without line break at the end.
func Printf(msg ...interface{}) {
	runAdapters(MessageLog, FormattedOut, msg...)
}

// Debugln shows debug message on stdout with line break at the end.
// If debug mode is not active no message is displayed
func Debugln(msg ...interface{}) {
	runAdapters(DebugLog, LineOut, msg...)
}

// Debugf shows debug message on stdout without line break at the end.
// If debug mode is not active no message is displayed
func Debugf(msg ...interface{}) {
	runAdapters(DebugLog, FormattedOut, msg...)
}

// DefaultAdapter of log package
func DefaultAdapter(m MsgType, o OutType, config map[string]interface{}, msg ...interface{}) {
	if m == DebugLog && !DebugMode {
		return
	}

	var debugInfo, lineBreak, output string

	if DebugMode {
		_, fn, line, _ := runtime.Caller(5)
		fn = filepath.Base(fn)
		debugInfo = fmt.Sprintf("%s:%d ", fn, line)
	}

	if o == FormattedOut {
		output = fmt.Sprintf(msg[0].(string), msg[1:]...)
	} else {
		output = fmt.Sprint(msg...)
		lineBreak = "\n"
	}

	if EnableANSIColors {
		output = fmt.Sprintf("%s%s [%s] %s%s\033[0;00m",
			Colors[m],
			now().Format(TimeFormat),
			Prefixes[m],
			debugInfo,
			output)
	} else {
		output = fmt.Sprintf("%s [%s] %s%s",
			now().Format(TimeFormat),
			Prefixes[m],
			debugInfo,
			output)
	}

	if len(output) > MaxLineSize {
		output = output[:MaxLineSize] + "..."
	}
	output = output + lineBreak
	fmt.Print(output)
}
<|endoftext|>


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

package logger

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

const (
	defaultStackSize        = 8192
	defaultEventChannelSize = 1024
	maxNWriteErrors         = 5
)

// EventWriter is the backend of the logger package. It takes events and writes
// them to a storage, this can for example be a file, a database or the
// terminal.
type EventWriter interface {
	// Write is called every time a Log operation is called. This call should
	// block until the event is written. Advised is to buffer the events. All
	// calls to Write are synchronous.
	//
	// If an error is returned the event is expected to NOT have been written. The
	// event will written again after the error handler is called. If the
	// EventWriter returns 5 errors in a row the EventWriter is consided to be bad
	// and will be removed from the list of event writers. HandlerError will be
	// called with ErrBadEventWriter if this happens.
	Write(Event) error

	// HandleError is called every time Write returns an error.
	HandleError(error)

	// Close is called on the EventWriter once Close() (on the package) is called.
	Close() error
}

var (
	eventChannel       = make(chan Event, defaultEventChannelSize)
	eventChannelClosed = make(chan struct{}, 1) // Can't block.
	eventWriters       []EventWriter
	started            bool
)

// Start starts the logger package and enables writing to the given
// EventWriters.
func Start(ews ...EventWriter) {
	if started {
		panic("logger: can only Start once")
	} else if len(ews) < 1 {
		panic("logger: need atleast a single EventWriter to write to")
	}

	started = true
	eventWriters = ews

	go writeEvents()
}

var ErrBadEventWriter = fmt.Errorf("EventWriter is bad, more then %d faulty writes, EventWriter will be dropped", maxNWriteErrors)

// Needs to be run in it's own goroutine, it blocks until eventChannel is
// closed. After eventChannel is closed it sends a signal to eventChannelClosed.
func writeEvents() {
	var wg sync.WaitGroup
	wg.Add(len(eventWriters))

	// Create event sub channels for each EventWriter and start each EventWriter.
	var eventSubChannels = make([]chan Event, len(eventWriters))
	for i, ew := range eventWriters {
		eventSubChannels[i] = make(chan Event, defaultEventChannelSize)
		go startEventWriter(ew, eventSubChannels[i], &wg)
	}

	// Fanout the events to all the sub channels.
	for event := range eventChannel {
		for _, eventSubChannel := range eventSubChannels {
			eventSubChannel <- event
		}
	}

	// Close each sub channel and wait for their close signal.
	for _, eventSubChannel := range eventSubChannels {
		close(eventSubChannel)
	}

	wg.Wait()
	eventChannelClosed <- struct{}{}
}

// Must run in it's own go routine, it blocks until the events channel is
// closed. After the events channels is closed it sends a signal to the closed
// channel.
func startEventWriter(ew EventWriter, events <-chan Event, wg *sync.WaitGroup) {
	var badEventWriter = false

	for event := range events {
		if badEventWriter {
			// Simply drain the channel.
			// todo: improve this, don't send to the channel anymore if the writer is
			// bad.
			continue
		}

		if err := writeEvent(ew, event); err != nil {
			// At this point the EventWriter is bad and we won't write to it anymore.
			ew.HandleError(err)
			badEventWriter = true
		}
	}

	wg.Done()
}

// WriteEvent tries to write the event to the given EventWriter, it tries it up
// to maxNWriteErrors times. If EventWriter.Write returns an error it gets
// passed to the error handler of the EventWriter. This function either returns
// ErrBadEventWriter or nil as an error.
func writeEvent(ew EventWriter, event Event) error {
	for n := 1; n <= maxNWriteErrors; n++ {
		err := ew.Write(event)
		if err == nil {
			return nil
		}

		// Handle the error and try again.
		ew.HandleError(err)
	}

	return ErrBadEventWriter
}

// Close stops all the Log Operations from being usable, and they will panic if
// used after close is called. It also closes all EventWriters and returns the
// first returned error. The EventWriters are closed in the order they are
// passed to Start.
func Close() error {
	close(eventChannel)
	<-eventChannelClosed

	var err error
	for _, eventWriter := range eventWriters {
		er := eventWriter.Close()
		if er != nil && err == nil {
			err = er
		}
	}
	return err
}

// Subbed for testing.
var now = func() time.Time {
	return time.Now()
}

// Debug logs a debug message.
func Debug(tags Tags, msg string) {
	eventChannel <- Event{DebugEvent, now(), tags, msg, nil}
}

// Debugf is a formatted function of Debug.
func Debugf(tags Tags, format string, v ...interface{}) {
	Debug(tags, fmt.Sprintf(format, v...))
}

// Info logs an informational message.
func Info(tags Tags, msg string) {
	eventChannel <- Event{InfoEvent, now(), tags, msg, nil}
}

// Infof is a formatted function of Info.
func Infof(tags Tags, format string, v ...interface{}) {
	Info(tags, fmt.Sprintf(format, v...))
}

// Warn logs a warning message.
func Warn(tags Tags, msg string) {
	eventChannel <- Event{WarnEvent, now(), tags, msg, nil}
}

// Warnf is a formatted function of Warn.
func Warnf(tags Tags, format string, v ...interface{}) {
	Warn(tags, fmt.Sprintf(format, v...))
}

// Error logs an error message.
func Error(tags Tags, err error) {
	eventChannel <- Event{ErrorEvent, now(), tags, err.Error(), nil}
}

// Errorf is a formatted function of Error.
func Errorf(tags Tags, format string, v ...interface{}) {
	Error(tags, fmt.Errorf(format, v...))
}

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

	msg := interfaceToString(recv)
	eventChannel <- Event{FatalEvent, now(), tags, msg, stackTrace}
}

// 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 Thumbstone(tags Tags, functionName string) {
	var msg string
	if pc, file, line, ok := runtime.Caller(2); 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"
	}

	eventChannel <- Event{ThumbEvent, now(), tags, msg, nil}
}

// Log logs a custom created event.
//
// Note: the timestamp doesn't need to be set, because it will be set by Log.
func Log(event Event) {
	event.Timestamp = now()
	eventChannel <- event
}

// interfaceToString converts a interface{} variable to a string.
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>Move startEventWriter WaitGroup outside the function<commit_after>// Copyright (C) 2015 Thomas de Zeeuw.
//
// Licensed under the MIT license that can be found in the LICENSE file.

package logger

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

const (
	defaultStackSize        = 8192
	defaultEventChannelSize = 1024
	maxNWriteErrors         = 5
)

// EventWriter is the backend of the logger package. It takes events and writes
// them to a storage, this can for example be a file, a database or the
// terminal.
type EventWriter interface {
	// Write is called every time a Log operation is called. This call should
	// block until the event is written. Advised is to buffer the events. All
	// calls to Write are synchronous.
	//
	// If an error is returned the event is expected to NOT have been written. The
	// event will written again after the error handler is called. If the
	// EventWriter returns 5 errors in a row the EventWriter is consided to be bad
	// and will be removed from the list of event writers. HandlerError will be
	// called with ErrBadEventWriter if this happens.
	Write(Event) error

	// HandleError is called every time Write returns an error.
	HandleError(error)

	// Close is called on the EventWriter once Close() (on the package) is called.
	Close() error
}

var (
	eventChannel       = make(chan Event, defaultEventChannelSize)
	eventChannelClosed = make(chan struct{}, 1) // Can't block.
	eventWriters       []EventWriter
	started            bool
)

// Start starts the logger package and enables writing to the given
// EventWriters.
func Start(ews ...EventWriter) {
	if started {
		panic("logger: can only Start once")
	} else if len(ews) < 1 {
		panic("logger: need atleast a single EventWriter to write to")
	}

	started = true
	eventWriters = ews

	go writeEvents()
}

var ErrBadEventWriter = fmt.Errorf("EventWriter is bad, more then %d faulty writes, EventWriter will be dropped", maxNWriteErrors)

// Needs to be run in it's own goroutine, it blocks until eventChannel is
// closed. After eventChannel is closed it sends a signal to eventChannelClosed.
func writeEvents() {
	var wg sync.WaitGroup
	wg.Add(len(eventWriters))

	// Create event sub channels for each EventWriter and start each EventWriter.
	var eventSubChannels = make([]chan Event, len(eventWriters))
	for i, ew := range eventWriters {
		eventSubChannels[i] = make(chan Event, defaultEventChannelSize)

		go func(wg *sync.WaitGroup) {
			startEventWriter(ew, eventSubChannels[i])
			wg.Done()
		}(&wg)
	}

	// Fanout the events to all the sub channels.
	for event := range eventChannel {
		for _, eventSubChannel := range eventSubChannels {
			eventSubChannel <- event
		}
	}

	// Close each sub channel and wait for their close signal.
	for _, eventSubChannel := range eventSubChannels {
		close(eventSubChannel)
	}

	wg.Wait()
	eventChannelClosed <- struct{}{}
}

// Must run in it's own go routine, it blocks until the events channel is
// closed. After the events channels is closed it sends a signal to the closed
// channel.
func startEventWriter(ew EventWriter, events <-chan Event) {
	var badEventWriter = false

	for event := range events {
		if badEventWriter {
			// Simply drain the channel.
			// todo: improve this, don't send to the channel anymore if the writer is
			// bad.
			continue
		}

		if err := writeEvent(ew, event); err != nil {
			// At this point the EventWriter is bad and we won't write to it anymore.
			ew.HandleError(err)
			badEventWriter = true
		}
	}
}

// WriteEvent tries to write the event to the given EventWriter, it tries it up
// to maxNWriteErrors times. If EventWriter.Write returns an error it gets
// passed to the error handler of the EventWriter. This function either returns
// ErrBadEventWriter or nil as an error.
func writeEvent(ew EventWriter, event Event) error {
	for n := 1; n <= maxNWriteErrors; n++ {
		err := ew.Write(event)
		if err == nil {
			return nil
		}

		// Handle the error and try again.
		ew.HandleError(err)
	}

	return ErrBadEventWriter
}

// Close stops all the Log Operations from being usable, and they will panic if
// used after close is called. It also closes all EventWriters and returns the
// first returned error. The EventWriters are closed in the order they are
// passed to Start.
func Close() error {
	close(eventChannel)
	<-eventChannelClosed

	var err error
	for _, eventWriter := range eventWriters {
		er := eventWriter.Close()
		if er != nil && err == nil {
			err = er
		}
	}
	return err
}

// Subbed for testing.
var now = func() time.Time {
	return time.Now()
}

// Debug logs a debug message.
func Debug(tags Tags, msg string) {
	eventChannel <- Event{DebugEvent, now(), tags, msg, nil}
}

// Debugf is a formatted function of Debug.
func Debugf(tags Tags, format string, v ...interface{}) {
	Debug(tags, fmt.Sprintf(format, v...))
}

// Info logs an informational message.
func Info(tags Tags, msg string) {
	eventChannel <- Event{InfoEvent, now(), tags, msg, nil}
}

// Infof is a formatted function of Info.
func Infof(tags Tags, format string, v ...interface{}) {
	Info(tags, fmt.Sprintf(format, v...))
}

// Warn logs a warning message.
func Warn(tags Tags, msg string) {
	eventChannel <- Event{WarnEvent, now(), tags, msg, nil}
}

// Warnf is a formatted function of Warn.
func Warnf(tags Tags, format string, v ...interface{}) {
	Warn(tags, fmt.Sprintf(format, v...))
}

// Error logs an error message.
func Error(tags Tags, err error) {
	eventChannel <- Event{ErrorEvent, now(), tags, err.Error(), nil}
}

// Errorf is a formatted function of Error.
func Errorf(tags Tags, format string, v ...interface{}) {
	Error(tags, fmt.Errorf(format, v...))
}

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

	msg := interfaceToString(recv)
	eventChannel <- Event{FatalEvent, now(), tags, msg, stackTrace}
}

// 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 Thumbstone(tags Tags, functionName string) {
	var msg string
	if pc, file, line, ok := runtime.Caller(2); 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"
	}

	eventChannel <- Event{ThumbEvent, now(), tags, msg, nil}
}

// Log logs a custom created event.
//
// Note: the timestamp doesn't need to be set, because it will be set by Log.
func Log(event Event) {
	event.Timestamp = now()
	eventChannel <- event
}

// interfaceToString converts a interface{} variable to a string.
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 log

import (
	"bytes"
	"fmt"
	"io"
	"os"
	"runtime"
	"strings"
	"sync"
	"time"
)

// Level identifies the sort of log: error, info, debug, etc.
// Level implements flag.Value interface and can be set via
// user defined flag.
type Level int32

const (
	FATAL Level = iota - 3
	ERROR
	WARNING
	INFO
	DEBUG
	VDEBUG
	VVDEBUG
	VVVDEBUG
)

func (l *Level) Set(v string) error {
	lvlName := strings.ToLower(v)
	for lvl, name := range levelNames {
		if name == lvlName {
			*l = lvl
			return nil
		}
	}

	return fmt.Errorf("log: unknown log level name: %q", v)
}

func (l Level) String() string {
	return levelNames[l]
}

var levelNames = map[Level]string{
	FATAL:    "fatal",
	ERROR:    "error",
	WARNING:  "warning",
	INFO:     "info",
	DEBUG:    "debug",
	VDEBUG:   "vdebug",
	VVDEBUG:  "vvdebug",
	VVVDEBUG: "vvvdebug",
}

type Logger struct {
	mu  sync.Mutex
	lvl Level
	w   io.Writer
}

func New(lvl Level) *Logger {
	return &Logger{lvl: lvl, w: os.Stderr}
}

func (l *Logger) print(lvl Level, args ...interface{}) {
	buf := &bytes.Buffer{}
	fmt.Fprintln(buf, args...)
	l.output(lvl, buf.Bytes())
}

func (l *Logger) printf(lvl Level, format string, args ...interface{}) {
	buf := &bytes.Buffer{}
	fmt.Fprintf(buf, format, args...)

	if buf.Len() == 0 {
		return
	}

	if buf.Bytes()[buf.Len()-1] != '\n' {
		buf.WriteByte('\n')
	}
	l.output(lvl, buf.Bytes())
}

func (l *Logger) output(lvl Level, buf []byte) {
	if lvl > l.lvl {
		return
	}

	h := l.header(lvl)

	l.mu.Lock()
	defer l.mu.Unlock()

	l.w.Write(h)
	l.w.Write(buf)
}

func (l *Logger) header(lvl Level) []byte {
	// header format:
	//  YY/MM/DD HH:MM:SS.UUUUUU file:line] LEVEL:

	t := time.Now()
	year, month, day := t.Date()
	year %= 1000
	hour, minute, second := t.Clock()
	usecond := t.Nanosecond() / 1e3

	_, file, line, ok := runtime.Caller(4)
	if !ok {
		file, line = "???", 0
	} else {
		index := strings.LastIndex(file, "/")
		if index != -1 && index != len(file) {
			file = file[index+1:]
		}
	}

	level := levelNames[lvl]

	// TODO: don't use Sprintf because it's slow.
	format := "%.2d/%.2d/%.2d %.2d:%.2d:%.2d.%.6d %s:%d] %s: "
	buf := &bytes.Buffer{}
	fmt.Fprintf(buf, format, day, month, year, hour, minute, second,
		usecond, file, line, level)

	return buf.Bytes()
}

// VVVDebug logs with VVVDEBUG level.
// Arguments are handled in the manner of fmt.Print.
func (l *Logger) VVVDebug(args ...interface{}) {
	l.print(VVVDEBUG, args...)
}

// VVVDebugf logs with VVVDEBUG level.
// Arguments are handled in the manner of fmt.Printf.
func (l *Logger) VVVDebugf(format string, args ...interface{}) {
	l.printf(VVVDEBUG, format, args...)
}

// VVDebug logs with VVDEBUG level.
// Arguments are handled in the manner of fmt.Print.
func (l *Logger) VVDebug(args ...interface{}) {
	l.print(VVDEBUG, args...)
}

// VVDebugf logs with VVDEBUG level.
// Arguments are handled in the manner of fmt.Printf.
func (l *Logger) VVDebugf(format string, args ...interface{}) {
	l.printf(VVDEBUG, format, args...)
}

// VDebug logs with VDEBUG level.
// Arguments are handled in the manner of fmt.Print.
func (l *Logger) VDebug(args ...interface{}) {
	l.print(VDEBUG, args...)
}

// VDebugf logs with VDEBUG level.
// Arguments are handled in the manner of fmt.Printf.
func (l *Logger) VDebugf(format string, args ...interface{}) {
	l.printf(VDEBUG, format, args...)
}

// Debug logs with DEBUG level.
// Arguments are handled in the manner of fmt.Print.
func (l *Logger) Debug(args ...interface{}) {
	l.print(DEBUG, args...)
}

// Debugf logs with DEBUG level.
// Arguments are handled in the manner of fmt.Printf.
func (l *Logger) Debugf(format string, args ...interface{}) {
	l.printf(DEBUG, format, args...)
}

// Info logs with INFO level.
// Arguments are handled in the manner of fmt.Print.
func (l *Logger) Info(args ...interface{}) {
	l.print(INFO, args...)
}

// Infof logs with INFO level.
// Arguments are handled in the manner of fmt.Printf.
func (l *Logger) Infof(format string, args ...interface{}) {
	l.printf(INFO, format, args...)
}

// Warning logs with WARNING level.
// Arguments are handled in the manner of fmt.Print.
func (l *Logger) Warning(args ...interface{}) {
	l.print(WARNING, args...)
}

// Warningf logs with WARNING level.
// Arguments are handled in the manner of fmt.Printf.
func (l *Logger) Warningf(format string, args ...interface{}) {
	l.printf(WARNING, format, args...)
}

// Error logs with ERROR level.
// Arguments are handled in the manner of fmt.Print.
func (l *Logger) Error(args ...interface{}) {
	l.print(ERROR, args...)
}

// Errorf logs with ERROR level.
// Arguments are handled in the manner of fmt.Printf.
func (l *Logger) Errorf(format string, args ...interface{}) {
	l.printf(ERROR, format, args...)
}

// Fatal logs with FATAL level, including a stack trace
// of all goroutins, than calls os.Exit(1).
// Arguments are handled in the manner of fmt.Print.
func (l *Logger) Fatal(args ...interface{}) {
	l.print(FATAL, args...)
	// TODO: print stack
	os.Exit(1)
}

// Fatalf logs with FATAL level, including a stack trace
// of all goroutins, than calls os.Exit(1).
// Arguments are handled in the manner of fmt.Printf.
func (l *Logger) Fatalf(format string, args ...interface{}) {
	l.printf(FATAL, format, args...)
	// TODO: print stack
	os.Exit(1)
}

// SetLevel sets log level.
// Logs at or above this level go to log writer.
func (l *Logger) SetLevel(lvl Level) {
	// TODO: use atomic and change lvl inplace.
	l.mu.Lock()
	defer l.mu.Unlock()
	l.lvl = lvl
}

var l = New(INFO)

// VVVDebug logs with VVVDEBUG level.
// Arguments are handled in the manner of fmt.Print.
func VVVDebug(args ...interface{}) {
	l.print(VVVDEBUG, args...)
}

// VVVDebugf logs with VVVDEBUG level.
// Arguments are handled in the manner of fmt.Printf.
func VVVDebugf(format string, args ...interface{}) {
	l.printf(VVVDEBUG, format, args...)
}

// VVDebug logs with VVDEBUG level.
// Arguments are handled in the manner of fmt.Print.
func VVDebug(args ...interface{}) {
	l.print(VVDEBUG, args...)
}

// VVDebugf logs with VVDEBUG level.
// Arguments are handled in the manner of fmt.Printf.
func VVDebugf(format string, args ...interface{}) {
	l.printf(VVDEBUG, format, args...)
}

// VDebug logs with VDEBUG level.
// Arguments are handled in the manner of fmt.Print.
func VDebug(args ...interface{}) {
	l.print(VDEBUG, args...)
}

// VDebugf logs with VDEBUG level.
// Arguments are handled in the manner of fmt.Printf.
func VDebugf(format string, args ...interface{}) {
	l.printf(VDEBUG, format, args...)
}

// Debug logs with DEBUG level.
// Arguments are handled in the manner of fmt.Print.
func Debug(args ...interface{}) {
	l.print(DEBUG, args...)
}

// Debugf logs with DEBUG level.
// Arguments are handled in the manner of fmt.Printf.
func Debugf(format string, args ...interface{}) {
	l.printf(DEBUG, format, args...)
}

// Info logs with INFO level.
// Arguments are handled in the manner of fmt.Print.
func Info(args ...interface{}) {
	l.print(INFO, args...)
}

// Infof logs with INFO level.
// Arguments are handled in the manner of fmt.Printf.
func Infof(format string, args ...interface{}) {
	l.printf(INFO, format, args...)
}

// Warning logs with WARNING level.
// Arguments are handled in the manner of fmt.Print.
func Warning(args ...interface{}) {
	l.print(WARNING, args...)
}

// Warningf logs with WARNING level.
// Arguments are handled in the manner of fmt.Printf.
func Warningf(format string, args ...interface{}) {
	l.printf(WARNING, format, args...)
}

// Error logs with ERROR level.
// Arguments are handled in the manner of fmt.Print.
func Error(args ...interface{}) {
	l.print(ERROR, args...)
}

// Errorf logs with ERROR level.
// Arguments are handled in the manner of fmt.Printf.
func Errorf(format string, args ...interface{}) {
	l.printf(ERROR, format, args...)
}

// Fatal logs with FATAL level, including a stack trace
// of all goroutins, than calls os.Exit(1).
// Arguments are handled in the manner of fmt.Print.
func Fatal(args ...interface{}) {
	l.print(FATAL, args...)
	// TODO: print stack
	os.Exit(1)
}

// Fatalf logs with FATAL level, including a stack trace
// of all goroutins, than calls os.Exit(1).
// Arguments are handled in the manner of fmt.Printf.
func Fatalf(format string, args ...interface{}) {
	l.printf(FATAL, format, args...)
	// TODO: print stack
	os.Exit(1)
}

// SetLevel sets log level.
// Logs at or above this level go to log writer.
func SetLevel(lvl Level) {
	l.SetLevel(lvl)
}
<commit_msg>implement json.[Unm|M]arshaling interfaces for Level<commit_after>package log

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io"
	"os"
	"runtime"
	"strings"
	"sync"
	"time"
)

// Level identifies the sort of log: error, info, debug, etc.
// Level implements flag.Value, json.Marshaler and json.Unmarshaler
// interfaces and can be set via user defined flag or json unmarshaling.
type Level int32

const (
	FATAL Level = iota - 3
	ERROR
	WARNING
	INFO
	DEBUG
	VDEBUG
	VVDEBUG
	VVVDEBUG
)

func (l *Level) Set(v string) error {
	lvlName := strings.ToLower(v)
	for lvl, name := range levelNames {
		if name == lvlName {
			*l = lvl
			return nil
		}
	}

	return fmt.Errorf("log: unknown log level name: %q", v)
}

func (l Level) String() string {
	return levelNames[l]
}

func (l *Level) UnmarshalJSON(data []byte) (err error) {
	var name string
	if err = json.Unmarshal(data, &name); err != nil {
		return
	}

	return l.Set(name)
}

func (l Level) MarshalJSON() ([]byte, error) {
	return json.Marshal(levelNames[l])
}

var levelNames = map[Level]string{
	FATAL:    "fatal",
	ERROR:    "error",
	WARNING:  "warning",
	INFO:     "info",
	DEBUG:    "debug",
	VDEBUG:   "vdebug",
	VVDEBUG:  "vvdebug",
	VVVDEBUG: "vvvdebug",
}

type Logger struct {
	mu  sync.Mutex
	lvl Level
	w   io.Writer
}

func New(lvl Level) *Logger {
	return &Logger{lvl: lvl, w: os.Stderr}
}

func (l *Logger) print(lvl Level, args ...interface{}) {
	buf := &bytes.Buffer{}
	fmt.Fprintln(buf, args...)
	l.output(lvl, buf.Bytes())
}

func (l *Logger) printf(lvl Level, format string, args ...interface{}) {
	buf := &bytes.Buffer{}
	fmt.Fprintf(buf, format, args...)

	if buf.Len() == 0 {
		return
	}

	if buf.Bytes()[buf.Len()-1] != '\n' {
		buf.WriteByte('\n')
	}
	l.output(lvl, buf.Bytes())
}

func (l *Logger) output(lvl Level, buf []byte) {
	if lvl > l.lvl {
		return
	}

	h := l.header(lvl)

	l.mu.Lock()
	defer l.mu.Unlock()

	l.w.Write(h)
	l.w.Write(buf)
}

func (l *Logger) header(lvl Level) []byte {
	// header format:
	//  YY/MM/DD HH:MM:SS.UUUUUU file:line] LEVEL:

	t := time.Now()
	year, month, day := t.Date()
	year %= 1000
	hour, minute, second := t.Clock()
	usecond := t.Nanosecond() / 1e3

	_, file, line, ok := runtime.Caller(4)
	if !ok {
		file, line = "???", 0
	} else {
		index := strings.LastIndex(file, "/")
		if index != -1 && index != len(file) {
			file = file[index+1:]
		}
	}

	level := levelNames[lvl]

	// TODO: don't use Sprintf because it's slow.
	format := "%.2d/%.2d/%.2d %.2d:%.2d:%.2d.%.6d %s:%d] %s: "
	buf := &bytes.Buffer{}
	fmt.Fprintf(buf, format, day, month, year, hour, minute, second,
		usecond, file, line, level)

	return buf.Bytes()
}

// VVVDebug logs with VVVDEBUG level.
// Arguments are handled in the manner of fmt.Print.
func (l *Logger) VVVDebug(args ...interface{}) {
	l.print(VVVDEBUG, args...)
}

// VVVDebugf logs with VVVDEBUG level.
// Arguments are handled in the manner of fmt.Printf.
func (l *Logger) VVVDebugf(format string, args ...interface{}) {
	l.printf(VVVDEBUG, format, args...)
}

// VVDebug logs with VVDEBUG level.
// Arguments are handled in the manner of fmt.Print.
func (l *Logger) VVDebug(args ...interface{}) {
	l.print(VVDEBUG, args...)
}

// VVDebugf logs with VVDEBUG level.
// Arguments are handled in the manner of fmt.Printf.
func (l *Logger) VVDebugf(format string, args ...interface{}) {
	l.printf(VVDEBUG, format, args...)
}

// VDebug logs with VDEBUG level.
// Arguments are handled in the manner of fmt.Print.
func (l *Logger) VDebug(args ...interface{}) {
	l.print(VDEBUG, args...)
}

// VDebugf logs with VDEBUG level.
// Arguments are handled in the manner of fmt.Printf.
func (l *Logger) VDebugf(format string, args ...interface{}) {
	l.printf(VDEBUG, format, args...)
}

// Debug logs with DEBUG level.
// Arguments are handled in the manner of fmt.Print.
func (l *Logger) Debug(args ...interface{}) {
	l.print(DEBUG, args...)
}

// Debugf logs with DEBUG level.
// Arguments are handled in the manner of fmt.Printf.
func (l *Logger) Debugf(format string, args ...interface{}) {
	l.printf(DEBUG, format, args...)
}

// Info logs with INFO level.
// Arguments are handled in the manner of fmt.Print.
func (l *Logger) Info(args ...interface{}) {
	l.print(INFO, args...)
}

// Infof logs with INFO level.
// Arguments are handled in the manner of fmt.Printf.
func (l *Logger) Infof(format string, args ...interface{}) {
	l.printf(INFO, format, args...)
}

// Warning logs with WARNING level.
// Arguments are handled in the manner of fmt.Print.
func (l *Logger) Warning(args ...interface{}) {
	l.print(WARNING, args...)
}

// Warningf logs with WARNING level.
// Arguments are handled in the manner of fmt.Printf.
func (l *Logger) Warningf(format string, args ...interface{}) {
	l.printf(WARNING, format, args...)
}

// Error logs with ERROR level.
// Arguments are handled in the manner of fmt.Print.
func (l *Logger) Error(args ...interface{}) {
	l.print(ERROR, args...)
}

// Errorf logs with ERROR level.
// Arguments are handled in the manner of fmt.Printf.
func (l *Logger) Errorf(format string, args ...interface{}) {
	l.printf(ERROR, format, args...)
}

// Fatal logs with FATAL level, including a stack trace
// of all goroutins, than calls os.Exit(1).
// Arguments are handled in the manner of fmt.Print.
func (l *Logger) Fatal(args ...interface{}) {
	l.print(FATAL, args...)
	// TODO: print stack
	os.Exit(1)
}

// Fatalf logs with FATAL level, including a stack trace
// of all goroutins, than calls os.Exit(1).
// Arguments are handled in the manner of fmt.Printf.
func (l *Logger) Fatalf(format string, args ...interface{}) {
	l.printf(FATAL, format, args...)
	// TODO: print stack
	os.Exit(1)
}

// SetLevel sets log level.
// Logs at or above this level go to log writer.
func (l *Logger) SetLevel(lvl Level) {
	// TODO: use atomic and change lvl inplace.
	l.mu.Lock()
	defer l.mu.Unlock()
	l.lvl = lvl
}

var l = New(INFO)

// VVVDebug logs with VVVDEBUG level.
// Arguments are handled in the manner of fmt.Print.
func VVVDebug(args ...interface{}) {
	l.print(VVVDEBUG, args...)
}

// VVVDebugf logs with VVVDEBUG level.
// Arguments are handled in the manner of fmt.Printf.
func VVVDebugf(format string, args ...interface{}) {
	l.printf(VVVDEBUG, format, args...)
}

// VVDebug logs with VVDEBUG level.
// Arguments are handled in the manner of fmt.Print.
func VVDebug(args ...interface{}) {
	l.print(VVDEBUG, args...)
}

// VVDebugf logs with VVDEBUG level.
// Arguments are handled in the manner of fmt.Printf.
func VVDebugf(format string, args ...interface{}) {
	l.printf(VVDEBUG, format, args...)
}

// VDebug logs with VDEBUG level.
// Arguments are handled in the manner of fmt.Print.
func VDebug(args ...interface{}) {
	l.print(VDEBUG, args...)
}

// VDebugf logs with VDEBUG level.
// Arguments are handled in the manner of fmt.Printf.
func VDebugf(format string, args ...interface{}) {
	l.printf(VDEBUG, format, args...)
}

// Debug logs with DEBUG level.
// Arguments are handled in the manner of fmt.Print.
func Debug(args ...interface{}) {
	l.print(DEBUG, args...)
}

// Debugf logs with DEBUG level.
// Arguments are handled in the manner of fmt.Printf.
func Debugf(format string, args ...interface{}) {
	l.printf(DEBUG, format, args...)
}

// Info logs with INFO level.
// Arguments are handled in the manner of fmt.Print.
func Info(args ...interface{}) {
	l.print(INFO, args...)
}

// Infof logs with INFO level.
// Arguments are handled in the manner of fmt.Printf.
func Infof(format string, args ...interface{}) {
	l.printf(INFO, format, args...)
}

// Warning logs with WARNING level.
// Arguments are handled in the manner of fmt.Print.
func Warning(args ...interface{}) {
	l.print(WARNING, args...)
}

// Warningf logs with WARNING level.
// Arguments are handled in the manner of fmt.Printf.
func Warningf(format string, args ...interface{}) {
	l.printf(WARNING, format, args...)
}

// Error logs with ERROR level.
// Arguments are handled in the manner of fmt.Print.
func Error(args ...interface{}) {
	l.print(ERROR, args...)
}

// Errorf logs with ERROR level.
// Arguments are handled in the manner of fmt.Printf.
func Errorf(format string, args ...interface{}) {
	l.printf(ERROR, format, args...)
}

// Fatal logs with FATAL level, including a stack trace
// of all goroutins, than calls os.Exit(1).
// Arguments are handled in the manner of fmt.Print.
func Fatal(args ...interface{}) {
	l.print(FATAL, args...)
	// TODO: print stack
	os.Exit(1)
}

// Fatalf logs with FATAL level, including a stack trace
// of all goroutins, than calls os.Exit(1).
// Arguments are handled in the manner of fmt.Printf.
func Fatalf(format string, args ...interface{}) {
	l.printf(FATAL, format, args...)
	// TODO: print stack
	os.Exit(1)
}

// SetLevel sets log level.
// Logs at or above this level go to log writer.
func SetLevel(lvl Level) {
	l.SetLevel(lvl)
}
<|endoftext|>


<commit_before>package wechat

import "go.uber.org/zap"

var Logger *zap.Logger
var Sugar *zap.SugaredLogger

func InitLogger(config ...zap.Config) {
	var conf zap.Config
	if len(config) > 1 {
		conf = config[0]
	} else {
		conf = zap.NewDevelopmentConfig()
		conf.DisableStacktrace = true
	}
	var err error
	Logger, err = conf.Build()
	if err != nil {
		panic(err)
	}
	Sugar = Logger.Sugar()
}
<commit_msg>Update files<commit_after>package wechat

import "go.uber.org/zap"

var Logger *zap.Logger
var Sugar *zap.SugaredLogger

func InitLogger(config ...zap.Config) {
	var conf zap.Config
	if len(config) > 1 {
		conf = config[0]
	} else {
		conf = zap.NewDevelopmentConfig()
		conf.DisableStacktrace = true
		conf.Level.SetLevel(zap.InfoLevel)
	}
	var err error
	Logger, err = conf.Build()
	if err != nil {
		panic(err)
	}
	Sugar = Logger.Sugar()
}
<|endoftext|>


<commit_before>// Package loglevel implements a simple levelled logging wrapper around the go
// "log" module
//
// The goal of this project is to be the simplest well-tested levelled logging
// wrapper around go's log module. It retains as much of the same API as possible.
package loglevel

import (
	"fmt"
	"io"
	"os"
	"strings"
)

var std = New(os.Stderr, "", LstdFlags, Pdebug)

// SetOutput sets the output destination for the standard logger
func SetOutput(out io.Writer) {
	std = New(out, std.Prefix(), std.Flags(), std.priority)
}

// Priority returns the output priority for the standard logger.
func Priority() int {
	return std.Priority()
}

// SetPriority sets the output priority for the standard logger.
func SetPriority(priority int) {
	std.SetPriority(priority)
}

// SetPriorityString sets the output priority by the name of a debug level
func SetPriorityString(s string) error {
	s = strings.ToUpper(s)
	for i, name := range priorityName {
		if name == s {
			SetPriority(i)
			return nil
		}
	}
	return fmt.Errorf("Unable to find priority %s", s)
}

// Flags returns the output layouts for the standard logger.
func Flags() int {
	return std.Flags()
}

// SetFlags sets the output layouts for the standard logger.
func SetFlags(flags int) {
	std.SetFlags(flags)
}

// SetPrefix sets the logger prefix
func SetPrefix(prefix string) {
	std.SetPrefix(prefix)
}

// Fatal prints the message it's given and quits the program
func Fatal(v ...interface{}) {
	std.Fatal(v...)
}

// Fatalf prints the message it's given and quits the program
func Fatalf(format string, v ...interface{}) {
	std.Fatalf(format, v...)
}

// Fatalln prints the message it's given and quits the program
func Fatalln(v ...interface{}) {
	std.Fatalln(v...)
}

// Panic prints the message it's given and panic()s the program
func Panic(v ...interface{}) {
	std.Panic(v...)
}

// Panicf prints the message it's given and panic()s the program
func Panicf(format string, v ...interface{}) {
	std.Panicf(format, v...)
}

// Panicln prints the message it's given and panic()s the program
func Panicln(v ...interface{}) {
	std.Panicln(v...)
}

// Error prints to the standard logger with the Error level.
func Error(v ...interface{}) {
	std.Error(v...)
}

// Errorf prints to the standard logger with the Error level.
func Errorf(format string, v ...interface{}) {
	std.Errorf(format, v...)
}

// Errorln prints to the standard logger with the Error level.
func Errorln(v ...interface{}) {
	std.Errorln(v...)
}

// Warn prints to the standard logger with the Warn level.
func Warn(v ...interface{}) {
	std.Warn(v...)
}

// Warnf prints to the standard logger with the Warn level.
func Warnf(format string, v ...interface{}) {
	std.Warnf(format, v...)
}

// Warnln prints to the standard logger with the Warn level.
func Warnln(v ...interface{}) {
	std.Warnln(v...)
}

// Info prints to the standard logger with the Info level.
func Info(v ...interface{}) {
	std.Info(v...)
}

// Infof prints to the standard logger with the Info level.
func Infof(format string, v ...interface{}) {
	std.Infof(format, v...)
}

// Infoln prints to the standard logger with the Info level.
func Infoln(v ...interface{}) {
	std.Infoln(v...)
}

// Debug prints to the standard logger with the Debug level.
func Debug(v ...interface{}) {
	std.Debug(v...)
}

// Debugf prints to the standard logger with the Debug level.
func Debugf(format string, v ...interface{}) {
	std.Debugf(format, v...)
}

// Debugln prints to the standard logger with the Debug level.
func Debugln(v ...interface{}) {
	std.Debugln(v...)
}

// Trace prints to the standard logger with the Trace level.
func Trace(v ...interface{}) {
	std.Trace(v...)
}

// Tracef prints to the standard logger with the Trace level.
func Tracef(format string, v ...interface{}) {
	std.Tracef(format, v...)
}

// Traceln prints to the standard logger with the Trace level.
func Traceln(v ...interface{}) {
	std.Traceln(v...)
}
<commit_msg>copy README text to package desc<commit_after>// Package loglevel aims to be the simplest and best-tested levelled logging
// wrapper around go's standard library log module. It retains as much of the
// same API as possible.
package loglevel

import (
	"fmt"
	"io"
	"os"
	"strings"
)

var std = New(os.Stderr, "", LstdFlags, Pdebug)

// SetOutput sets the output destination for the standard logger
func SetOutput(out io.Writer) {
	std = New(out, std.Prefix(), std.Flags(), std.priority)
}

// Priority returns the output priority for the standard logger.
func Priority() int {
	return std.Priority()
}

// SetPriority sets the output priority for the standard logger.
func SetPriority(priority int) {
	std.SetPriority(priority)
}

// SetPriorityString sets the output priority by the name of a debug level
func SetPriorityString(s string) error {
	s = strings.ToUpper(s)
	for i, name := range priorityName {
		if name == s {
			SetPriority(i)
			return nil
		}
	}
	return fmt.Errorf("Unable to find priority %s", s)
}

// Flags returns the output layouts for the standard logger.
func Flags() int {
	return std.Flags()
}

// SetFlags sets the output layouts for the standard logger.
func SetFlags(flags int) {
	std.SetFlags(flags)
}

// SetPrefix sets the logger prefix
func SetPrefix(prefix string) {
	std.SetPrefix(prefix)
}

// Fatal prints the message it's given and quits the program
func Fatal(v ...interface{}) {
	std.Fatal(v...)
}

// Fatalf prints the message it's given and quits the program
func Fatalf(format string, v ...interface{}) {
	std.Fatalf(format, v...)
}

// Fatalln prints the message it's given and quits the program
func Fatalln(v ...interface{}) {
	std.Fatalln(v...)
}

// Panic prints the message it's given and panic()s the program
func Panic(v ...interface{}) {
	std.Panic(v...)
}

// Panicf prints the message it's given and panic()s the program
func Panicf(format string, v ...interface{}) {
	std.Panicf(format, v...)
}

// Panicln prints the message it's given and panic()s the program
func Panicln(v ...interface{}) {
	std.Panicln(v...)
}

// Error prints to the standard logger with the Error level.
func Error(v ...interface{}) {
	std.Error(v...)
}

// Errorf prints to the standard logger with the Error level.
func Errorf(format string, v ...interface{}) {
	std.Errorf(format, v...)
}

// Errorln prints to the standard logger with the Error level.
func Errorln(v ...interface{}) {
	std.Errorln(v...)
}

// Warn prints to the standard logger with the Warn level.
func Warn(v ...interface{}) {
	std.Warn(v...)
}

// Warnf prints to the standard logger with the Warn level.
func Warnf(format string, v ...interface{}) {
	std.Warnf(format, v...)
}

// Warnln prints to the standard logger with the Warn level.
func Warnln(v ...interface{}) {
	std.Warnln(v...)
}

// Info prints to the standard logger with the Info level.
func Info(v ...interface{}) {
	std.Info(v...)
}

// Infof prints to the standard logger with the Info level.
func Infof(format string, v ...interface{}) {
	std.Infof(format, v...)
}

// Infoln prints to the standard logger with the Info level.
func Infoln(v ...interface{}) {
	std.Infoln(v...)
}

// Debug prints to the standard logger with the Debug level.
func Debug(v ...interface{}) {
	std.Debug(v...)
}

// Debugf prints to the standard logger with the Debug level.
func Debugf(format string, v ...interface{}) {
	std.Debugf(format, v...)
}

// Debugln prints to the standard logger with the Debug level.
func Debugln(v ...interface{}) {
	std.Debugln(v...)
}

// Trace prints to the standard logger with the Trace level.
func Trace(v ...interface{}) {
	std.Trace(v...)
}

// Tracef prints to the standard logger with the Trace level.
func Tracef(format string, v ...interface{}) {
	std.Tracef(format, v...)
}

// Traceln prints to the standard logger with the Trace level.
func Traceln(v ...interface{}) {
	std.Traceln(v...)
}
<|endoftext|>