starlog/core.go
2026-03-19 16:37:57 +08:00

1066 lines
29 KiB
Go

package starlog
import (
"context"
"errors"
"fmt"
"io"
"os"
"path/filepath"
"runtime"
"sort"
"strconv"
"strings"
"sync/atomic"
"time"
"unicode"
"unicode/utf8"
)
func generateCoreLogStr(skip int, logstr string) string {
var line int = 0
var funcname, fileName string
now := time.Now()
pc, fName, codeln, ok := runtime.Caller(skip)
if !ok {
return ""
}
line = codeln
funcname = runtime.FuncForPC(pc).Name()
funcname = filepath.Ext(funcname)
funcname = strings.TrimPrefix(funcname, ".")
fileName = filepath.Base(fName)
y, m, d := now.Date()
h, i, s := now.Clock()
micro := now.Nanosecond() / 1e3
logStr := fmt.Sprintf("%04d-%02d-%02d %02d:%02d:%02d.%06d", y, m, d, h, i, s, micro)
logStr += " " + fileName + ":" + strconv.Itoa(line)
logStr += " <" + funcname + ">"
logStr += " " + logstr
return logStr
}
func (logger *starlog) levelName(level int) string {
levelName, ok := levels[level]
if !ok {
return strconv.Itoa(level)
}
return levelName
}
func (logger *starlog) levelColor(level int) *Color {
color, ok := logger.colorMe[level]
if ok && color != nil {
return color
}
return NewColor(FgWhite)
}
func (logger *starlog) levelAttrs(level int) []Attr {
attrs, ok := logger.colorList[level]
if !ok {
return []Attr{FgWhite}
}
cloned := make([]Attr, len(attrs))
copy(cloned, attrs)
return cloned
}
func cloneLevelAttrsMap(source map[int][]Attr) map[int][]Attr {
if len(source) == 0 {
return map[int][]Attr{}
}
cloned := make(map[int][]Attr, len(source))
for level, attrs := range source {
attrCopy := make([]Attr, len(attrs))
copy(attrCopy, attrs)
cloned[level] = attrCopy
}
return cloned
}
func cloneLevelColorMap(source map[int][]Attr) map[int]*Color {
if len(source) == 0 {
return map[int]*Color{}
}
cloned := make(map[int]*Color, len(source))
for level, attrs := range source {
cloned[level] = NewColor(attrs...)
}
return cloned
}
func cloneStringSlice(source []string) []string {
if len(source) == 0 {
return nil
}
cloned := make([]string, len(source))
copy(cloned, source)
return cloned
}
func cloneKeywordColorizers(source map[string]*Color) map[string]*Color {
if len(source) == 0 {
return nil
}
cloned := make(map[string]*Color, len(source))
for key, colorizer := range source {
cloned[key] = colorizer
}
return cloned
}
type keywordPattern struct {
keyword string
keywordLower string
byteLen int
colorizer *Color
}
type keywordMatcher struct {
byFirstRune map[rune][]keywordPattern
byFirstRuneFold map[rune][]keywordPattern
}
func buildKeywordMatcher(order []string, colorizers map[string]*Color) *keywordMatcher {
if len(order) == 0 {
return nil
}
matcher := &keywordMatcher{
byFirstRune: make(map[rune][]keywordPattern),
byFirstRuneFold: make(map[rune][]keywordPattern),
}
for _, keyword := range order {
if keyword == "" {
continue
}
colorizer := colorizers[keyword]
if colorizer == nil {
continue
}
firstRune, _ := utf8.DecodeRuneInString(keyword)
if firstRune == utf8.RuneError {
continue
}
pattern := keywordPattern{
keyword: keyword,
keywordLower: strings.ToLower(keyword),
byteLen: len(keyword),
colorizer: colorizer,
}
matcher.byFirstRune[firstRune] = append(matcher.byFirstRune[firstRune], pattern)
matcher.byFirstRuneFold[unicode.ToLower(firstRune)] = append(matcher.byFirstRuneFold[unicode.ToLower(firstRune)], pattern)
}
if len(matcher.byFirstRune) == 0 {
return nil
}
return matcher
}
func (logger *starlog) rebuildKeywordCachesLocked() {
if logger.keywordColors == nil {
logger.keywordColors = make(map[string][]Attr)
}
keywords := make([]string, 0, len(logger.keywordColors))
var colorizers map[string]*Color
for keyword, attrs := range logger.keywordColors {
if keyword == "" {
continue
}
keywords = append(keywords, keyword)
if len(attrs) > 0 {
if colorizers == nil {
colorizers = make(map[string]*Color, len(logger.keywordColors))
}
colorizers[keyword] = NewColor(attrs...)
}
}
sort.Slice(keywords, func(i, j int) bool {
return len(keywords[i]) > len(keywords[j])
})
if len(keywords) == 0 {
keywords = nil
}
logger.keywordOrder = keywords
logger.keywordColorizers = colorizers
logger.keywordMatcher = buildKeywordMatcher(keywords, colorizers)
}
func (logger *starlog) snapshotForBuildLocked() *starlog {
colorAttrs := cloneLevelAttrsMap(logger.colorList)
return &starlog{
minLevel: logger.minLevel,
errOutputLevel: logger.errOutputLevel,
showFuncName: logger.showFuncName,
showThread: logger.showThread,
showLevel: logger.showLevel,
showDeatilFile: logger.showDeatilFile,
showColor: logger.showColor,
onlyColorLevel: logger.onlyColorLevel,
autoAppendNewline: logger.autoAppendNewline,
stopWriter: logger.stopWriter,
name: logger.name,
colorList: colorAttrs,
colorMe: cloneLevelColorMap(colorAttrs),
keywordColors: nil,
keywordOrder: nil,
keywordColorizers: nil,
keywordMatcher: logger.keywordMatcher,
keywordMatchOptions: logger.keywordMatchOptions,
showFieldColor: logger.showFieldColor,
fieldKeyColor: cloneAttrs(logger.fieldKeyColor),
fieldTypeColors: cloneColorMap(logger.fieldTypeColors),
fieldValueColors: cloneColorMap(logger.fieldValueColors),
entryHandler: logger.entryHandler,
redactor: logger.redactor,
redactRules: cloneRedactRules(logger.redactRules),
redactFailMode: logger.redactFailMode,
redactMaskToken: logger.redactMaskToken,
entryHandlerTimeout: logger.entryHandlerTimeout,
formatter: logger.formatter,
contextFields: logger.contextFields,
}
}
func (logger *starlog) formatTime(now time.Time) string {
y, m, d := now.Date()
h, i, s := now.Clock()
micro := now.Nanosecond() / 1e3
return fmt.Sprintf("%04d-%02d-%02d %02d:%02d:%02d.%06d", y, m, d, h, i, s, micro)
}
func (logger *starlog) buildMeta(fileName string, line int, funcname string, thread string) string {
parts := make([]string, 0, 3)
if logger.showDeatilFile {
parts = append(parts, fileName+":"+strconv.Itoa(line))
}
if logger.showFuncName {
parts = append(parts, "<"+funcname+">")
}
if logger.showThread {
parts = append(parts, "|"+thread+"|")
}
return strings.Join(parts, " ")
}
func (logger *starlog) composeLine(timestamp string, meta string, levelTag string, message string) string {
parts := make([]string, 0, 4)
parts = append(parts, timestamp)
if meta != "" {
parts = append(parts, meta)
}
if logger.showLevel && levelTag != "" {
parts = append(parts, levelTag)
}
parts = append(parts, message)
return strings.Join(parts, " ")
}
func appendNewlineIfNeeded(text string, autoAppend bool) string {
if !autoAppend || text == "" {
return text
}
if strings.HasSuffix(text, "\n") {
return text
}
return text + "\n"
}
func (logger *starlog) highlightKeywords(text string) string {
if logger.keywordMatcher != nil {
if highlighted, changed := logger.keywordMatcher.highlight(text, logger.keywordMatchOptions); changed {
return highlighted
}
return text
}
if len(logger.keywordColors) == 0 {
return text
}
keywords := logger.keywordOrder
if len(keywords) == 0 {
keywords = make([]string, 0, len(logger.keywordColors))
for keyword := range logger.keywordColors {
if keyword == "" {
continue
}
keywords = append(keywords, keyword)
}
if len(keywords) == 0 {
return text
}
sort.Slice(keywords, func(i, j int) bool {
return len(keywords[i]) > len(keywords[j])
})
}
highlighted := text
for _, keyword := range keywords {
attrs := logger.keywordColors[keyword]
if len(attrs) == 0 {
continue
}
colorizer := logger.keywordColorizers[keyword]
highlighted = highlightKeywordText(highlighted, keyword, attrs, logger.keywordMatchOptions, colorizer)
}
return highlighted
}
func isWordRune(r rune) bool {
return r == '_' || unicode.IsLetter(r) || unicode.IsDigit(r)
}
func hasWordBoundary(text string, start int, end int) bool {
if start < 0 || end < start || end > len(text) {
return false
}
leftBoundary := true
if start > 0 {
r, _ := utf8.DecodeLastRuneInString(text[:start])
leftBoundary = !isWordRune(r)
}
rightBoundary := true
if end < len(text) {
r, _ := utf8.DecodeRuneInString(text[end:])
rightBoundary = !isWordRune(r)
}
return leftBoundary && rightBoundary
}
func (matcher *keywordMatcher) highlight(text string, opts KeywordMatchOptions) (string, bool) {
if matcher == nil || text == "" {
return text, false
}
var builder strings.Builder
builder.Grow(len(text) + 32)
last := 0
changed := false
for idx := 0; idx < len(text); {
r, size := utf8.DecodeRuneInString(text[idx:])
if size <= 0 {
size = 1
}
next := idx + size
var patterns []keywordPattern
if opts.IgnoreCase {
patterns = matcher.byFirstRuneFold[unicode.ToLower(r)]
} else {
patterns = matcher.byFirstRune[r]
}
matched := false
for _, pattern := range patterns {
matchEnd := idx + pattern.byteLen
if matchEnd > len(text) {
continue
}
candidate := text[idx:matchEnd]
ok := false
if opts.IgnoreCase {
ok = strings.EqualFold(candidate, pattern.keyword)
} else {
ok = candidate == pattern.keyword
}
if !ok {
continue
}
if opts.WholeWord && !hasWordBoundary(text, idx, matchEnd) {
continue
}
builder.WriteString(text[last:idx])
if pattern.colorizer != nil {
builder.WriteString(pattern.colorizer.Sprint(candidate))
} else {
builder.WriteString(candidate)
}
last = matchEnd
idx = matchEnd
matched = true
changed = true
break
}
if matched {
continue
}
if r == utf8.RuneError && size == 1 {
idx++
continue
}
idx = next
}
if !changed {
return text, false
}
builder.WriteString(text[last:])
return builder.String(), true
}
func highlightKeywordText(text string, keyword string, attrs []Attr, opts KeywordMatchOptions, colorizer *Color) string {
if text == "" || keyword == "" || len(attrs) == 0 {
return text
}
if colorizer == nil {
colorizer = NewColor(attrs...)
}
if !opts.IgnoreCase && !opts.WholeWord {
return strings.ReplaceAll(text, keyword, colorizer.Sprint(keyword))
}
var builder strings.Builder
builder.Grow(len(text) + 32)
changed := false
last := 0
for idx := 0; idx < len(text); {
r, size := utf8.DecodeRuneInString(text[idx:])
if size <= 0 {
size = 1
}
next := idx + size
matchEnd := idx + len(keyword)
if matchEnd <= len(text) {
candidate := text[idx:matchEnd]
matched := false
if opts.IgnoreCase {
matched = strings.EqualFold(candidate, keyword)
} else {
matched = candidate == keyword
}
if matched {
if !opts.WholeWord || hasWordBoundary(text, idx, matchEnd) {
builder.WriteString(text[last:idx])
builder.WriteString(colorizer.Sprint(candidate))
last = matchEnd
idx = matchEnd
changed = true
continue
}
}
}
if r == utf8.RuneError && size == 1 {
idx++
continue
}
idx = next
}
if !changed {
return text
}
builder.WriteString(text[last:])
return builder.String()
}
func (logger *starlog) formatPlainFromEntry(entry *Entry, defaultLine string) string {
if logger.formatter == nil {
return defaultLine
}
formatted, err := logger.formatter.Format(entry)
if err != nil || len(formatted) == 0 {
return defaultLine
}
return string(formatted)
}
func (logger *starlog) renderEntryMessage(entry *Entry) string {
if entry == nil {
return ""
}
parts := make([]string, 0, 3)
if entry.Message != "" {
parts = append(parts, entry.Message)
}
if entry.Err != nil {
parts = append(parts, "error="+entry.Err.Error())
}
fieldText := renderFields(entry.Fields)
if fieldText != "" {
parts = append(parts, fieldText)
}
return strings.Join(parts, " ")
}
func fieldTypeName(value interface{}) string {
switch value.(type) {
case nil:
return FieldTypeNil
case bool:
return FieldTypeBool
case string:
return FieldTypeString
case error:
return FieldTypeError
case int, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64, float32, float64:
return FieldTypeNumber
default:
return FieldTypeOther
}
}
func (logger *starlog) renderDisplayFieldValue(key string, value interface{}) string {
raw := fmt.Sprintf("%v", value)
if !logger.showFieldColor {
return raw
}
if attrs, ok := logger.fieldValueColors[key]; ok && len(attrs) > 0 {
return NewColor(attrs...).Sprint(raw)
}
typeName := fieldTypeName(value)
if attrs, ok := logger.fieldTypeColors[typeName]; ok && len(attrs) > 0 {
return NewColor(attrs...).Sprint(raw)
}
return raw
}
func (logger *starlog) renderDisplayFields(fields Fields) string {
if len(fields) == 0 {
return ""
}
keys := make([]string, 0, len(fields))
for key := range fields {
keys = append(keys, key)
}
sort.Strings(keys)
items := make([]string, 0, len(keys))
for _, key := range keys {
keyText := key
if logger.showFieldColor && len(logger.fieldKeyColor) > 0 {
keyText = NewColor(logger.fieldKeyColor...).Sprint(keyText)
}
valueText := logger.renderDisplayFieldValue(key, fields[key])
items = append(items, keyText+"="+valueText)
}
return strings.Join(items, " ")
}
func (logger *starlog) renderDisplayMessage(entry *Entry) string {
if entry == nil {
return ""
}
parts := make([]string, 0, 2)
base := entry.Message
if entry.Err != nil {
if base != "" {
base += " "
}
base += "error=" + entry.Err.Error()
}
if base != "" {
parts = append(parts, logger.highlightKeywords(base))
}
fieldText := logger.renderDisplayFields(entry.Fields)
if fieldText != "" {
parts = append(parts, fieldText)
}
return strings.Join(parts, " ")
}
func (logger *starlog) flushPendingWritesLocked(name string, colors []Attr) {
if logger.switching {
return
}
for len(logger.pendingWrites) > 0 {
if logger.switching {
return
}
logStr := logger.pendingWrites[0]
logger.pendingWrites = logger.pendingWrites[1:]
logger.signalPendingCondLocked()
if err := logger.writeDirect(logStr); err != nil {
reportWriteError(err, LogData{
Name: name,
Log: logStr,
Colors: colors,
})
}
}
}
func (logger *starlog) signalPendingCondLocked() {
if logger.pendingCond != nil {
logger.pendingCond.Broadcast()
}
}
func (logger *starlog) updatePendingPeakLocked() {
current := uint64(len(logger.pendingWrites))
for {
peak := atomic.LoadUint64(&logger.pendingPeakLen)
if current <= peak {
return
}
if atomic.CompareAndSwapUint64(&logger.pendingPeakLen, peak, current) {
return
}
}
}
func (logger *starlog) writeDirect(logStr string) error {
if logger.sink != nil {
return logger.sink.Write([]byte(logStr))
}
if logger.output == nil {
return nil
}
_, err := logger.output.Write([]byte(logStr))
return err
}
func (logger *starlog) enqueuePendingWriteLocked(logStr string, data LogData) bool {
for logger.switching && logger.pendingWriteLimit > 0 && len(logger.pendingWrites) >= logger.pendingWriteLimit {
switch logger.pendingDropPolicy {
case PendingDropNewest:
atomic.AddUint64(&logger.pendingDropCount, 1)
reportWriteError(ErrPendingWriteDropped, data)
return true
case PendingBlock:
atomic.AddUint64(&logger.pendingBlockCount, 1)
if logger.pendingCond == nil {
atomic.AddUint64(&logger.pendingDropCount, 1)
reportWriteError(ErrPendingWriteDropped, data)
return true
}
logger.pendingCond.Wait()
default:
atomic.AddUint64(&logger.pendingDropCount, 1)
dropData := data
dropData.Log = logger.pendingWrites[0]
logger.pendingWrites = logger.pendingWrites[1:]
logger.signalPendingCondLocked()
reportWriteError(ErrPendingWriteDropped, dropData)
}
}
if !logger.switching {
return false
}
logger.pendingWrites = append(logger.pendingWrites, logStr)
logger.updatePendingPeakLocked()
return true
}
func (logger *starlog) invokeEntryHandler(handler Handler, timeout time.Duration, entry *Entry, data LogData) {
if handler == nil || entry == nil {
return
}
handlerCtx := entry.Context
if handlerCtx == nil {
handlerCtx = context.Background()
}
run := func() {
defer func() {
if panicErr := recover(); panicErr != nil {
reportAsyncDrop(fmt.Errorf("%w: %v", ErrAsyncHandlerPanic, panicErr), data)
}
}()
if err := handler.Handle(handlerCtx, entry); err != nil {
reportWriteError(err, data)
}
}
if timeout <= 0 {
run()
return
}
done := make(chan struct{}, 1)
go func() {
run()
done <- struct{}{}
}()
select {
case <-done:
case <-time.After(timeout):
reportAsyncDrop(ErrAsyncHandlerTimeout, data)
}
}
func (logger *starlog) enqueueAsyncTransfer(transfer logTransfer, fallbackSync bool) {
StartStacks()
if stacks == nil {
reportAsyncDrop(io.ErrClosedPipe, transfer.LogData)
if fallbackSync && GetAsyncFallbackToSync() {
invokeAsyncHandlerSafely(transfer.handlerFunc, transfer.LogData)
}
return
}
if err := stacks.TryPush(transfer); err != nil {
if errors.Is(err, errStackFull) {
reportAsyncDrop(ErrAsyncQueueFull, transfer.LogData)
} else {
reportAsyncDrop(err, transfer.LogData)
}
if fallbackSync && GetAsyncFallbackToSync() {
invokeAsyncHandlerSafely(transfer.handlerFunc, transfer.LogData)
}
}
}
func (logger *starlog) build(thread string, isStd bool, isShow bool, handler func(data LogData), level int, logDetail string, fields Fields, logErr error, ctx context.Context) {
logger.mu.Lock()
snapshot := logger.snapshotForBuildLocked()
logger.mu.Unlock()
if level < snapshot.minLevel {
return
}
var skip, line int = 3, 0
var funcname, fileName string
now := time.Now()
if isStd {
skip++
}
if snapshot.showDeatilFile || snapshot.showFuncName {
pc, fName, codeln, ok := runtime.Caller(skip)
if !ok {
return
}
line = codeln
funcname = runtime.FuncForPC(pc).Name()
funcname = filepath.Ext(funcname)
funcname = strings.TrimPrefix(funcname, ".")
fileName = filepath.Base(fName)
}
levelName := snapshot.levelName(level)
levelTag := "[" + levelName + "]"
timestamp := snapshot.formatTime(now)
meta := snapshot.buildMeta(fileName, line, funcname, thread)
contextFields := Fields(nil)
if ctx != nil && snapshot.contextFields != nil {
contextFields = snapshot.contextFields(ctx)
}
mergedFields := mergeFields(fields, contextFields)
entry := &Entry{
Time: now,
Level: level,
LevelName: levelName,
LoggerName: snapshot.name,
Thread: thread,
File: fileName,
Line: line,
Func: funcname,
Message: logDetail,
Fields: mergedFields,
Err: logErr,
Context: ctx,
}
if !logger.applyRedaction(snapshot, entry) {
return
}
if !logger.allowByDedup(entry) {
return
}
if !logger.allowBySampling(entry) {
return
}
if !logger.allowByRateLimit(entry) {
return
}
messageText := snapshot.renderEntryMessage(entry)
defaultPlain := snapshot.composeLine(timestamp, meta, levelTag, messageText)
plainLine := snapshot.formatPlainFromEntry(entry, defaultPlain)
plainLine = appendNewlineIfNeeded(plainLine, snapshot.autoAppendNewline)
displayLine := plainLine
logData := LogData{
Log: plainLine,
Colors: snapshot.levelAttrs(level),
Name: snapshot.name,
}
if isShow && snapshot.showColor {
if snapshot.onlyColorLevel && snapshot.formatter == nil {
levelSegment := levelTag
if snapshot.showLevel {
levelSegment = snapshot.levelColor(level).Sprint(levelTag)
}
messageSegment := snapshot.renderDisplayMessage(entry)
displayLine = snapshot.composeLine(timestamp, meta, levelSegment, messageSegment)
} else {
displayLine = snapshot.levelColor(level).Sprint(plainLine)
}
}
if isShow {
if level < snapshot.errOutputLevel {
if snapshot.showColor {
if _, err := fmt.Fprint(stdScreen, displayLine); err != nil {
reportWriteError(err, logData)
}
} else {
if _, err := fmt.Fprint(os.Stdout, displayLine); err != nil {
reportWriteError(err, logData)
}
}
} else {
if snapshot.showColor {
if _, err := fmt.Fprint(errScreen, displayLine); err != nil {
reportWriteError(err, logData)
}
} else {
if _, err := fmt.Fprint(os.Stderr, displayLine); err != nil {
reportWriteError(err, logData)
}
}
}
}
if handler != nil {
logger.enqueueAsyncTransfer(logTransfer{
handlerFunc: handler,
LogData: logData,
}, true)
}
if snapshot.entryHandler != nil {
entryCopy := *entry
logger.enqueueAsyncTransfer(logTransfer{
handlerFunc: func(data LogData) {
entryVal := entryCopy
logger.invokeEntryHandler(snapshot.entryHandler, snapshot.entryHandlerTimeout, &entryVal, data)
},
LogData: logData,
}, false)
}
if !snapshot.stopWriter {
logger.writeWithData(plainLine, logData)
}
}
func (logger *starlog) write(logStr string) {
logger.writeWithData(logStr, LogData{Log: logStr})
}
func (logger *starlog) writeWithData(logStr string, data LogData) {
logger.mu.Lock()
defer logger.mu.Unlock()
if logger.stopWriter {
return
}
if data.Name == "" {
data.Name = logger.name
}
logStr = appendNewlineIfNeeded(logStr, logger.autoAppendNewline)
data.Log = logStr
if logger.switching {
if logger.enqueuePendingWriteLocked(logStr, data) {
return
}
}
logger.flushPendingWritesLocked(data.Name, data.Colors)
if err := logger.writeDirect(logStr); err != nil {
reportWriteError(err, data)
}
}
func (logger *starlog) writePendingLocked() {
if logger.stopWriter {
logger.pendingWrites = nil
logger.signalPendingCondLocked()
return
}
logger.flushPendingWritesLocked(logger.name, nil)
logger.signalPendingCondLocked()
}
func (logger *starlog) print(str ...interface{}) string {
return fmt.Sprint(str...)
}
func (logger *starlog) printf(format string, str ...interface{}) string {
return fmt.Sprintf(format, str...)
}
func (logger *starlog) println(str ...interface{}) string {
return fmt.Sprintln(str...)
}
func (logger *starlog) Debug(thread string, isStd bool, handler func(LogData), str ...interface{}) {
strs := fmt.Sprint(str...)
logger.build(thread, isStd, logger.showStd, handler, LvDebug, strs, nil, nil, nil)
}
func (logger *starlog) Debugf(thread string, isStd bool, handler func(LogData), format string, str ...interface{}) {
strs := fmt.Sprintf(format, str...)
logger.build(thread, isStd, logger.showStd, handler, LvDebug, strs, nil, nil, nil)
}
func (logger *starlog) Debugln(thread string, isStd bool, handler func(LogData), str ...interface{}) {
strs := fmt.Sprintln(str...)
logger.build(thread, isStd, logger.showStd, handler, LvDebug, strs, nil, nil, nil)
}
func (logger *starlog) Info(thread string, isStd bool, handler func(LogData), str ...interface{}) {
strs := fmt.Sprint(str...)
logger.build(thread, isStd, logger.showStd, handler, LvInfo, strs, nil, nil, nil)
}
func (logger *starlog) Infof(thread string, isStd bool, handler func(LogData), format string, str ...interface{}) {
strs := fmt.Sprintf(format, str...)
logger.build(thread, isStd, logger.showStd, handler, LvInfo, strs, nil, nil, nil)
}
func (logger *starlog) Infoln(thread string, isStd bool, handler func(LogData), str ...interface{}) {
strs := fmt.Sprintln(str...)
logger.build(thread, isStd, logger.showStd, handler, LvInfo, strs, nil, nil, nil)
}
func (logger *starlog) Notice(thread string, isStd bool, handler func(LogData), str ...interface{}) {
strs := fmt.Sprint(str...)
logger.build(thread, isStd, logger.showStd, handler, LvNotice, strs, nil, nil, nil)
}
func (logger *starlog) Noticef(thread string, isStd bool, handler func(LogData), format string, str ...interface{}) {
strs := fmt.Sprintf(format, str...)
logger.build(thread, isStd, logger.showStd, handler, LvNotice, strs, nil, nil, nil)
}
func (logger *starlog) Noticeln(thread string, isStd bool, handler func(LogData), str ...interface{}) {
strs := fmt.Sprintln(str...)
logger.build(thread, isStd, logger.showStd, handler, LvNotice, strs, nil, nil, nil)
}
func (logger *starlog) Warning(thread string, isStd bool, handler func(LogData), str ...interface{}) {
strs := fmt.Sprint(str...)
logger.build(thread, isStd, logger.showStd, handler, LvWarning, strs, nil, nil, nil)
}
func (logger *starlog) Warningf(thread string, isStd bool, handler func(LogData), format string, str ...interface{}) {
strs := fmt.Sprintf(format, str...)
logger.build(thread, isStd, logger.showStd, handler, LvWarning, strs, nil, nil, nil)
}
func (logger *starlog) Warningln(thread string, isStd bool, handler func(LogData), str ...interface{}) {
strs := fmt.Sprintln(str...)
logger.build(thread, isStd, logger.showStd, handler, LvWarning, strs, nil, nil, nil)
}
func (logger *starlog) Error(thread string, isStd bool, handler func(LogData), str ...interface{}) {
strs := fmt.Sprint(str...)
logger.build(thread, isStd, logger.showStd, handler, LvError, strs, nil, nil, nil)
}
func (logger *starlog) Errorf(thread string, isStd bool, handler func(LogData), format string, str ...interface{}) {
strs := fmt.Sprintf(format, str...)
logger.build(thread, isStd, logger.showStd, handler, LvError, strs, nil, nil, nil)
}
func (logger *starlog) Errorln(thread string, isStd bool, handler func(LogData), str ...interface{}) {
strs := fmt.Sprintln(str...)
logger.build(thread, isStd, logger.showStd, handler, LvError, strs, nil, nil, nil)
}
func (logger *starlog) Critical(thread string, isStd bool, handler func(LogData), str ...interface{}) {
strs := fmt.Sprint(str...)
logger.build(thread, isStd, logger.showStd, handler, LvCritical, strs, nil, nil, nil)
}
func (logger *starlog) Criticalf(thread string, isStd bool, handler func(LogData), format string, str ...interface{}) {
strs := fmt.Sprintf(format, str...)
logger.build(thread, isStd, logger.showStd, handler, LvCritical, strs, nil, nil, nil)
}
func (logger *starlog) Criticalln(thread string, isStd bool, handler func(LogData), str ...interface{}) {
strs := fmt.Sprintln(str...)
logger.build(thread, isStd, logger.showStd, handler, LvCritical, strs, nil, nil, nil)
}
func (logger *starlog) Fatal(thread string, isStd bool, handler func(LogData), str ...interface{}) {
strs := fmt.Sprint(str...)
logger.build(thread, isStd, logger.showStd, handler, LvFatal, strs, nil, nil, nil)
os.Exit(9)
}
func (logger *starlog) Fatalf(thread string, isStd bool, handler func(LogData), format string, str ...interface{}) {
strs := fmt.Sprintf(format, str...)
logger.build(thread, isStd, logger.showStd, handler, LvFatal, strs, nil, nil, nil)
os.Exit(9)
}
func (logger *starlog) Fatalln(thread string, isStd bool, handler func(LogData), str ...interface{}) {
strs := fmt.Sprintln(str...)
logger.build(thread, isStd, logger.showStd, handler, LvFatal, strs, nil, nil, nil)
os.Exit(9)
}
func (logger *starlog) Panic(thread string, isStd bool, handler func(LogData), str ...interface{}) {
strs := fmt.Sprint(str...)
logger.build(thread, isStd, logger.showStd, handler, LvPanic, strs, nil, nil, nil)
panic(str)
}
func (logger *starlog) Panicf(thread string, isStd bool, handler func(LogData), format string, str ...interface{}) {
strs := fmt.Sprintf(format, str...)
logger.build(thread, isStd, logger.showStd, handler, LvPanic, strs, nil, nil, nil)
panic(fmt.Sprintf(format, str...))
}
func (logger *starlog) Panicln(thread string, isStd bool, handler func(LogData), str ...interface{}) {
strs := fmt.Sprintln(str...)
logger.build(thread, isStd, logger.showStd, handler, LvPanic, strs, nil, nil, nil)
panic(fmt.Sprintln(str...))
}
func (logger *starlog) Print(thread string, isStd bool, isShow bool, handler func(LogData), str ...interface{}) {
strs := fmt.Sprint(str...)
if isShow {
fmt.Print(strs)
}
logger.write(strs)
}
func (logger *starlog) Printf(thread string, isStd bool, isShow bool, handler func(LogData), format string, str ...interface{}) {
strs := fmt.Sprintf(format, str...)
if isShow {
fmt.Print(strs)
}
logger.write(strs)
}
func (logger *starlog) Println(thread string, isStd bool, isShow bool, handler func(LogData), str ...interface{}) {
strs := fmt.Sprintln(str...)
if isShow {
fmt.Print(strs)
}
logger.write(strs)
}
func (logger *starlog) Log(thread string, isStd bool, isShow bool, level int, handler func(LogData), str ...interface{}) {
strs := fmt.Sprint(str...)
logger.build(thread, isStd, isShow, handler, level, strs, nil, nil, nil)
}
func (logger *starlog) Logf(thread string, isStd bool, isShow bool, level int, handler func(LogData), format string, str ...interface{}) {
strs := fmt.Sprintf(format, str...)
logger.build(thread, isStd, isShow, handler, level, strs, nil, nil, nil)
}
func (logger *starlog) Logln(thread string, isStd bool, isShow bool, level int, handler func(LogData), str ...interface{}) {
strs := fmt.Sprintln(str...)
logger.build(thread, isStd, isShow, handler, level, strs, nil, nil, nil)
}
func (logger *starlog) Write(str ...interface{}) {
strs := fmt.Sprint(str...)
logger.write(strs)
}
func (logger *starlog) Writef(format string, str ...interface{}) {
strs := fmt.Sprintf(format, str...)
logger.Write(strs)
}
func (logger *starlog) Writeln(str ...interface{}) {
strs := fmt.Sprintln(str...)
logger.Write(strs)
}