github.com/nikandfor/tlog@v0.21.5-0.20231108111739-3ef89426a96d/wire.go (about)

     1  package tlog
     2  
     3  import (
     4  	"unicode/utf8"
     5  	_ "unsafe"
     6  
     7  	"github.com/nikandfor/loc"
     8  
     9  	"github.com/nikandfor/tlog/low"
    10  	"github.com/nikandfor/tlog/tlwire"
    11  )
    12  
    13  type (
    14  	RawMessage []byte
    15  
    16  	Modify []byte
    17  
    18  	Timestamp int64
    19  
    20  	FormatNext string
    21  
    22  	format struct {
    23  		Fmt  string
    24  		Args []interface{}
    25  	}
    26  )
    27  
    28  const KeyAuto = ""
    29  
    30  var (
    31  	Hidden        = RawMessage{tlwire.Special | tlwire.Hidden}
    32  	None          = RawMessage{tlwire.Special | tlwire.None}
    33  	Nil           = RawMessage{tlwire.Special | tlwire.Nil}
    34  	Break         = RawMessage{tlwire.Special | tlwire.Break}
    35  	NextAsHex     = Modify{tlwire.Semantic | tlwire.Hex}
    36  	NextAsMessage = Modify{tlwire.Semantic | WireMessage}
    37  	NextAsType    = FormatNext("%T")
    38  )
    39  
    40  const (
    41  	WireLabel = tlwire.SemanticTlogBase + iota
    42  	WireID
    43  	WireMessage
    44  	WireEventKind
    45  	WireLogLevel
    46  
    47  	_
    48  	_
    49  	_
    50  	_
    51  	_
    52  
    53  	SemanticUserBase
    54  )
    55  
    56  var (
    57  	e tlwire.Encoder
    58  	d tlwire.Decoder
    59  )
    60  
    61  func AppendLabels(b []byte, kvs []interface{}) []byte {
    62  	const tag = tlwire.Semantic | WireLabel
    63  
    64  	w := len(b)
    65  	b = append(b, low.Spaces[:len(kvs)/2+1]...)
    66  	r := len(b)
    67  
    68  	b = AppendKVs(b, kvs)
    69  
    70  	for r < len(b) {
    71  		end := d.Skip(b, r)
    72  
    73  		w += copy(b[w:], b[r:end])
    74  		r = end
    75  
    76  		end = d.Skip(b, r)
    77  
    78  		if b[r] != tag {
    79  			b[w] = tag
    80  			w++
    81  		}
    82  
    83  		w += copy(b[w:], b[r:end])
    84  		r = end
    85  	}
    86  
    87  	return b[:w]
    88  }
    89  
    90  func AppendKVs(b []byte, kvs []interface{}) []byte {
    91  	return appendKVs0(b, kvs)
    92  }
    93  
    94  func NextIs(semantic int) Modify {
    95  	return Modify(tlwire.LowEncoder{}.AppendTag(nil, tlwire.Semantic, semantic))
    96  }
    97  
    98  func RawTag(tag byte, sub int) RawMessage {
    99  	return RawMessage(tlwire.LowEncoder{}.AppendTag(nil, tag, sub))
   100  }
   101  
   102  func Special(value int) RawMessage {
   103  	return RawMessage(tlwire.LowEncoder{}.AppendTag(nil, tlwire.Special, value))
   104  }
   105  
   106  //go:linkname appendKVs0 github.com/nikandfor/tlog.appendKVs
   107  //go:noescape
   108  func appendKVs0(b []byte, kvs []interface{}) []byte
   109  
   110  func init() { // prevent deadcode warnings
   111  	appendKVs(nil, nil)
   112  }
   113  
   114  func appendKVs(b []byte, kvs []interface{}) []byte {
   115  	for i := 0; i < len(kvs); {
   116  		var k string
   117  
   118  		switch el := kvs[i].(type) {
   119  		case string:
   120  			k = el
   121  
   122  			if k == KeyAuto {
   123  				k = autoKey(kvs[i:])
   124  			}
   125  
   126  			i++
   127  		case RawMessage:
   128  			b = append(b, el...)
   129  			i++
   130  			continue
   131  		case tlwire.TlogAppender:
   132  			b = el.TlogAppend(b)
   133  			i++
   134  			continue
   135  		default:
   136  			k = "MISSING_KEY"
   137  		}
   138  
   139  		b = e.AppendString(b, k)
   140  
   141  	value:
   142  		if i == len(kvs) {
   143  			b = append(b, tlwire.Special|tlwire.Undefined)
   144  			break
   145  		}
   146  
   147  		switch v := kvs[i].(type) {
   148  		case string:
   149  			b = e.AppendString(b, v)
   150  		case int:
   151  			b = e.AppendInt(b, v)
   152  		case RawMessage:
   153  			b = append(b, v...)
   154  		case Modify:
   155  			b = append(b, v...)
   156  			i++
   157  
   158  			goto value
   159  		case FormatNext:
   160  			i++
   161  			if i == len(kvs) {
   162  				b = append(b, tlwire.Special|tlwire.Undefined)
   163  				break
   164  			}
   165  
   166  			b = e.AppendFormat(b, string(v), kvs[i])
   167  		default:
   168  			b = e.AppendValue(b, v)
   169  		}
   170  
   171  		i++
   172  	}
   173  
   174  	return b
   175  }
   176  
   177  func autoKey(kvs []interface{}) (k string) {
   178  	if len(kvs) == 1 {
   179  		return "MISSING_VALUE"
   180  	}
   181  
   182  	switch kvs[1].(type) {
   183  	//	case Message:
   184  	//		k = KeyMessage
   185  	case ID:
   186  		k = KeySpan
   187  	case LogLevel:
   188  		k = KeyLogLevel
   189  	case EventKind:
   190  		k = KeyEventKind
   191  	case loc.PC:
   192  		k = KeyCaller
   193  	case loc.PCs:
   194  		k = KeyCaller
   195  	default:
   196  		k = "UNSUPPORTED_AUTO_KEY"
   197  	}
   198  
   199  	return
   200  }
   201  
   202  func (ek EventKind) String() string {
   203  	return string(ek)
   204  }
   205  
   206  func (id ID) TlogAppend(b []byte) []byte {
   207  	b = append(b, tlwire.Semantic|WireID)
   208  	return e.AppendBytes(b, id[:])
   209  }
   210  
   211  func (id *ID) TlogParse(p []byte, i int) int {
   212  	if p[i] != tlwire.Semantic|WireID {
   213  		panic("not an id")
   214  	}
   215  
   216  	i++
   217  
   218  	if p[i] != tlwire.Bytes|16 {
   219  		panic("not an id")
   220  	}
   221  
   222  	i++
   223  
   224  	i += copy((*id)[:], p[i:])
   225  
   226  	return i
   227  }
   228  
   229  func (ek EventKind) TlogAppend(b []byte) []byte {
   230  	b = append(b, tlwire.Semantic|WireEventKind)
   231  	return e.AppendString(b, string(ek))
   232  }
   233  
   234  func (ek *EventKind) TlogParse(p []byte, i int) int {
   235  	if p[i] != tlwire.Semantic|WireEventKind {
   236  		panic("not an event type")
   237  	}
   238  
   239  	i++
   240  
   241  	v, i := d.Bytes(p, i)
   242  
   243  	r, w := utf8.DecodeRune(v)
   244  	if w == utf8.RuneError || w != len(v) {
   245  		panic("bad rune")
   246  	}
   247  
   248  	*ek = EventKind(r)
   249  
   250  	return i
   251  }
   252  
   253  func (l LogLevel) TlogAppend(b []byte) []byte {
   254  	b = append(b, tlwire.Semantic|WireLogLevel)
   255  	return e.AppendInt(b, int(l))
   256  }
   257  
   258  func (l *LogLevel) TlogParse(p []byte, i int) int {
   259  	if p[i] != tlwire.Semantic|WireLogLevel {
   260  		panic("not a log level")
   261  	}
   262  
   263  	i++
   264  
   265  	v, i := d.Signed(p, i)
   266  
   267  	*l = LogLevel(v)
   268  
   269  	return i
   270  }
   271  
   272  func (r RawMessage) TlogAppend(b []byte) []byte {
   273  	return append(b, r...)
   274  }
   275  
   276  func (r *RawMessage) TlogParse(p []byte, st int) (i int) {
   277  	i = d.Skip(p, st)
   278  	*r = append((*r)[:0], p[st:i]...)
   279  	return i
   280  }