// Copyright (c) 2016 Uber Technologies, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

package zapcore

import (
	
	
	
	

	
	
	
	
)

var _cePool = pool.New(func() *CheckedEntry {
	// Pre-allocate some space for cores.
	return &CheckedEntry{
		cores: make([]Core, 4),
	}
})

func getCheckedEntry() *CheckedEntry {
	 := _cePool.Get()
	.reset()
	return 
}

func putCheckedEntry( *CheckedEntry) {
	if  == nil {
		return
	}
	_cePool.Put()
}

// NewEntryCaller makes an EntryCaller from the return signature of
// runtime.Caller.
func ( uintptr,  string,  int,  bool) EntryCaller {
	if ! {
		return EntryCaller{}
	}
	return EntryCaller{
		PC:      ,
		File:    ,
		Line:    ,
		Defined: true,
	}
}

// EntryCaller represents the caller of a logging function.
type EntryCaller struct {
	Defined  bool
	PC       uintptr
	File     string
	Line     int
	Function string
}

// String returns the full path and line number of the caller.
func ( EntryCaller) () string {
	return .FullPath()
}

// FullPath returns a /full/path/to/package/file:line description of the
// caller.
func ( EntryCaller) () string {
	if !.Defined {
		return "undefined"
	}
	 := bufferpool.Get()
	.AppendString(.File)
	.AppendByte(':')
	.AppendInt(int64(.Line))
	 := .String()
	.Free()
	return 
}

// TrimmedPath returns a package/file:line description of the caller,
// preserving only the leaf directory name and file name.
func ( EntryCaller) () string {
	if !.Defined {
		return "undefined"
	}
	// nb. To make sure we trim the path correctly on Windows too, we
	// counter-intuitively need to use '/' and *not* os.PathSeparator here,
	// because the path given originates from Go stdlib, specifically
	// runtime.Caller() which (as of Mar/17) returns forward slashes even on
	// Windows.
	//
	// See https://github.com/golang/go/issues/3335
	// and https://github.com/golang/go/issues/18151
	//
	// for discussion on the issue on Go side.
	//
	// Find the last separator.
	//
	 := strings.LastIndexByte(.File, '/')
	if  == -1 {
		return .FullPath()
	}
	// Find the penultimate separator.
	 = strings.LastIndexByte(.File[:], '/')
	if  == -1 {
		return .FullPath()
	}
	 := bufferpool.Get()
	// Keep everything after the penultimate separator.
	.AppendString(.File[+1:])
	.AppendByte(':')
	.AppendInt(int64(.Line))
	 := .String()
	.Free()
	return 
}

// An Entry represents a complete log message. The entry's structured context
// is already serialized, but the log level, time, message, and call site
// information are available for inspection and modification. Any fields left
// empty will be omitted when encoding.
//
// Entries are pooled, so any functions that accept them MUST be careful not to
// retain references to them.
type Entry struct {
	Level      Level
	Time       time.Time
	LoggerName string
	Message    string
	Caller     EntryCaller
	Stack      string
}

// CheckWriteHook is a custom action that may be executed after an entry is
// written.
//
// Register one on a CheckedEntry with the After method.
//
//	if ce := logger.Check(...); ce != nil {
//	  ce = ce.After(hook)
//	  ce.Write(...)
//	}
//
// You can configure the hook for Fatal log statements at the logger level with
// the zap.WithFatalHook option.
type CheckWriteHook interface {
	// OnWrite is invoked with the CheckedEntry that was written and a list
	// of fields added with that entry.
	//
	// The list of fields DOES NOT include fields that were already added
	// to the logger with the With method.
	OnWrite(*CheckedEntry, []Field)
}

// CheckWriteAction indicates what action to take after a log entry is
// processed. Actions are ordered in increasing severity.
type CheckWriteAction uint8

const (
	// WriteThenNoop indicates that nothing special needs to be done. It's the
	// default behavior.
	WriteThenNoop CheckWriteAction = iota
	// WriteThenGoexit runs runtime.Goexit after Write.
	WriteThenGoexit
	// WriteThenPanic causes a panic after Write.
	WriteThenPanic
	// WriteThenFatal causes an os.Exit(1) after Write.
	WriteThenFatal
)

// OnWrite implements the OnWrite method to keep CheckWriteAction compatible
// with the new CheckWriteHook interface which deprecates CheckWriteAction.
func ( CheckWriteAction) ( *CheckedEntry,  []Field) {
	switch  {
	case WriteThenGoexit:
		runtime.Goexit()
	case WriteThenPanic:
		panic(.Message)
	case WriteThenFatal:
		exit.With(1)
	}
}

var _ CheckWriteHook = CheckWriteAction(0)

// CheckedEntry is an Entry together with a collection of Cores that have
// already agreed to log it.
//
// CheckedEntry references should be created by calling AddCore or After on a
// nil *CheckedEntry. References are returned to a pool after Write, and MUST
// NOT be retained after calling their Write method.
type CheckedEntry struct {
	Entry
	ErrorOutput WriteSyncer
	dirty       bool // best-effort detection of pool misuse
	after       CheckWriteHook
	cores       []Core
}

func ( *CheckedEntry) () {
	.Entry = Entry{}
	.ErrorOutput = nil
	.dirty = false
	.after = nil
	for  := range .cores {
		// don't keep references to cores
		.cores[] = nil
	}
	.cores = .cores[:0]
}

// Write writes the entry to the stored Cores, returns any errors, and returns
// the CheckedEntry reference to a pool for immediate re-use. Finally, it
// executes any required CheckWriteAction.
func ( *CheckedEntry) ( ...Field) {
	if  == nil {
		return
	}

	if .dirty {
		if .ErrorOutput != nil {
			// Make a best effort to detect unsafe re-use of this CheckedEntry.
			// If the entry is dirty, log an internal error; because the
			// CheckedEntry is being used after it was returned to the pool,
			// the message may be an amalgamation from multiple call sites.
			fmt.Fprintf(.ErrorOutput, "%v Unsafe CheckedEntry re-use near Entry %+v.\n", .Time, .Entry)
			_ = .ErrorOutput.Sync() // ignore error
		}
		return
	}
	.dirty = true

	var  error
	for  := range .cores {
		 = multierr.Append(, .cores[].Write(.Entry, ))
	}
	if  != nil && .ErrorOutput != nil {
		fmt.Fprintf(.ErrorOutput, "%v write error: %v\n", .Time, )
		_ = .ErrorOutput.Sync() // ignore error
	}

	 := .after
	if  != nil {
		.OnWrite(, )
	}
	putCheckedEntry()
}

// AddCore adds a Core that has agreed to log this CheckedEntry. It's intended to be
// used by Core.Check implementations, and is safe to call on nil CheckedEntry
// references.
func ( *CheckedEntry) ( Entry,  Core) *CheckedEntry {
	if  == nil {
		 = getCheckedEntry()
		.Entry = 
	}
	.cores = append(.cores, )
	return 
}

// Should sets this CheckedEntry's CheckWriteAction, which controls whether a
// Core will panic or fatal after writing this log entry. Like AddCore, it's
// safe to call on nil CheckedEntry references.
//
// Deprecated: Use [CheckedEntry.After] instead.
func ( *CheckedEntry) ( Entry,  CheckWriteAction) *CheckedEntry {
	return .After(, )
}

// After sets this CheckEntry's CheckWriteHook, which will be called after this
// log entry has been written. It's safe to call this on nil CheckedEntry
// references.
func ( *CheckedEntry) ( Entry,  CheckWriteHook) *CheckedEntry {
	if  == nil {
		 = getCheckedEntry()
		.Entry = 
	}
	.after = 
	return 
}