get.pme.sh/pnats@v0.0.0-20240304004023-26bb5a137ed0/server/msgtrace.go (about)

     1  // Copyright 2024 The NATS Authors
     2  // Licensed under the Apache License, Version 2.0 (the "License");
     3  // you may not use this file except in compliance with the License.
     4  // You may obtain a copy of the License at
     5  //
     6  // http://www.apache.org/licenses/LICENSE-2.0
     7  //
     8  // Unless required by applicable law or agreed to in writing, software
     9  // distributed under the License is distributed on an "AS IS" BASIS,
    10  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    11  // See the License for the specific language governing permissions and
    12  // limitations under the License.
    13  
    14  package server
    15  
    16  import (
    17  	"bytes"
    18  	"encoding/json"
    19  	"fmt"
    20  	"math/rand"
    21  	"strconv"
    22  	"strings"
    23  	"sync/atomic"
    24  	"time"
    25  )
    26  
    27  const (
    28  	MsgTraceDest          = "Nats-Trace-Dest"
    29  	MsgTraceHop           = "Nats-Trace-Hop"
    30  	MsgTraceOriginAccount = "Nats-Trace-Origin-Account"
    31  	MsgTraceOnly          = "Nats-Trace-Only"
    32  
    33  	// External trace header. Note that this header is normally in lower
    34  	// case (https://www.w3.org/TR/trace-context/#header-name). Vendors
    35  	// MUST expect the header in any case (upper, lower, mixed), and
    36  	// SHOULD send the header name in lowercase.
    37  	traceParentHdr = "traceparent"
    38  )
    39  
    40  type MsgTraceType string
    41  
    42  // Type of message trace events in the MsgTraceEvents list.
    43  // This is needed to unmarshal the list.
    44  const (
    45  	MsgTraceIngressType        = "in"
    46  	MsgTraceSubjectMappingType = "sm"
    47  	MsgTraceStreamExportType   = "se"
    48  	MsgTraceServiceImportType  = "si"
    49  	MsgTraceJetStreamType      = "js"
    50  	MsgTraceEgressType         = "eg"
    51  )
    52  
    53  type MsgTraceEvent struct {
    54  	Server  ServerInfo      `json:"server"`
    55  	Request MsgTraceRequest `json:"request"`
    56  	Hops    int             `json:"hops,omitempty"`
    57  	Events  MsgTraceEvents  `json:"events"`
    58  }
    59  
    60  type MsgTraceRequest struct {
    61  	// We are not making this an http.Header so that header name case is preserved.
    62  	Header  map[string][]string `json:"header,omitempty"`
    63  	MsgSize int                 `json:"msgsize,omitempty"`
    64  }
    65  
    66  type MsgTraceEvents []MsgTrace
    67  
    68  type MsgTrace interface {
    69  	new() MsgTrace
    70  	typ() MsgTraceType
    71  }
    72  
    73  type MsgTraceBase struct {
    74  	Type      MsgTraceType `json:"type"`
    75  	Timestamp time.Time    `json:"ts"`
    76  }
    77  
    78  type MsgTraceIngress struct {
    79  	MsgTraceBase
    80  	Kind    int    `json:"kind"`
    81  	CID     uint64 `json:"cid"`
    82  	Name    string `json:"name,omitempty"`
    83  	Account string `json:"acc"`
    84  	Subject string `json:"subj"`
    85  	Error   string `json:"error,omitempty"`
    86  }
    87  
    88  type MsgTraceSubjectMapping struct {
    89  	MsgTraceBase
    90  	MappedTo string `json:"to"`
    91  }
    92  
    93  type MsgTraceStreamExport struct {
    94  	MsgTraceBase
    95  	Account string `json:"acc"`
    96  	To      string `json:"to"`
    97  }
    98  
    99  type MsgTraceServiceImport struct {
   100  	MsgTraceBase
   101  	Account string `json:"acc"`
   102  	From    string `json:"from"`
   103  	To      string `json:"to"`
   104  }
   105  
   106  type MsgTraceJetStream struct {
   107  	MsgTraceBase
   108  	Stream     string `json:"stream"`
   109  	Subject    string `json:"subject,omitempty"`
   110  	NoInterest bool   `json:"nointerest,omitempty"`
   111  	Error      string `json:"error,omitempty"`
   112  }
   113  
   114  type MsgTraceEgress struct {
   115  	MsgTraceBase
   116  	Kind         int    `json:"kind"`
   117  	CID          uint64 `json:"cid"`
   118  	Name         string `json:"name,omitempty"`
   119  	Hop          string `json:"hop,omitempty"`
   120  	Account      string `json:"acc,omitempty"`
   121  	Subscription string `json:"sub,omitempty"`
   122  	Queue        string `json:"queue,omitempty"`
   123  	Error        string `json:"error,omitempty"`
   124  
   125  	// This is for applications that unmarshal the trace events
   126  	// and want to link an egress to route/leaf/gateway with
   127  	// the MsgTraceEvent from that server.
   128  	Link *MsgTraceEvent `json:"-"`
   129  }
   130  
   131  // -------------------------------------------------------------
   132  
   133  func (t MsgTraceBase) typ() MsgTraceType     { return t.Type }
   134  func (MsgTraceIngress) new() MsgTrace        { return &MsgTraceIngress{} }
   135  func (MsgTraceSubjectMapping) new() MsgTrace { return &MsgTraceSubjectMapping{} }
   136  func (MsgTraceStreamExport) new() MsgTrace   { return &MsgTraceStreamExport{} }
   137  func (MsgTraceServiceImport) new() MsgTrace  { return &MsgTraceServiceImport{} }
   138  func (MsgTraceJetStream) new() MsgTrace      { return &MsgTraceJetStream{} }
   139  func (MsgTraceEgress) new() MsgTrace         { return &MsgTraceEgress{} }
   140  
   141  var msgTraceInterfaces = map[MsgTraceType]MsgTrace{
   142  	MsgTraceIngressType:        MsgTraceIngress{},
   143  	MsgTraceSubjectMappingType: MsgTraceSubjectMapping{},
   144  	MsgTraceStreamExportType:   MsgTraceStreamExport{},
   145  	MsgTraceServiceImportType:  MsgTraceServiceImport{},
   146  	MsgTraceJetStreamType:      MsgTraceJetStream{},
   147  	MsgTraceEgressType:         MsgTraceEgress{},
   148  }
   149  
   150  func (t *MsgTraceEvents) UnmarshalJSON(data []byte) error {
   151  	var raw []json.RawMessage
   152  	err := json.Unmarshal(data, &raw)
   153  	if err != nil {
   154  		return err
   155  	}
   156  	*t = make(MsgTraceEvents, len(raw))
   157  	var tt MsgTraceBase
   158  	for i, r := range raw {
   159  		if err = json.Unmarshal(r, &tt); err != nil {
   160  			return err
   161  		}
   162  		tr, ok := msgTraceInterfaces[tt.Type]
   163  		if !ok {
   164  			return fmt.Errorf("unknown trace type %v", tt.Type)
   165  		}
   166  		te := tr.new()
   167  		if err := json.Unmarshal(r, te); err != nil {
   168  			return err
   169  		}
   170  		(*t)[i] = te
   171  	}
   172  	return nil
   173  }
   174  
   175  func getTraceAs[T MsgTrace](e any) *T {
   176  	v, ok := e.(*T)
   177  	if ok {
   178  		return v
   179  	}
   180  	return nil
   181  }
   182  
   183  func (t *MsgTraceEvent) Ingress() *MsgTraceIngress {
   184  	if len(t.Events) < 1 {
   185  		return nil
   186  	}
   187  	return getTraceAs[MsgTraceIngress](t.Events[0])
   188  }
   189  
   190  func (t *MsgTraceEvent) SubjectMapping() *MsgTraceSubjectMapping {
   191  	for _, e := range t.Events {
   192  		if e.typ() == MsgTraceSubjectMappingType {
   193  			return getTraceAs[MsgTraceSubjectMapping](e)
   194  		}
   195  	}
   196  	return nil
   197  }
   198  
   199  func (t *MsgTraceEvent) StreamExports() []*MsgTraceStreamExport {
   200  	var se []*MsgTraceStreamExport
   201  	for _, e := range t.Events {
   202  		if e.typ() == MsgTraceStreamExportType {
   203  			se = append(se, getTraceAs[MsgTraceStreamExport](e))
   204  		}
   205  	}
   206  	return se
   207  }
   208  
   209  func (t *MsgTraceEvent) ServiceImports() []*MsgTraceServiceImport {
   210  	var si []*MsgTraceServiceImport
   211  	for _, e := range t.Events {
   212  		if e.typ() == MsgTraceServiceImportType {
   213  			si = append(si, getTraceAs[MsgTraceServiceImport](e))
   214  		}
   215  	}
   216  	return si
   217  }
   218  
   219  func (t *MsgTraceEvent) JetStream() *MsgTraceJetStream {
   220  	for _, e := range t.Events {
   221  		if e.typ() == MsgTraceJetStreamType {
   222  			return getTraceAs[MsgTraceJetStream](e)
   223  		}
   224  	}
   225  	return nil
   226  }
   227  
   228  func (t *MsgTraceEvent) Egresses() []*MsgTraceEgress {
   229  	var eg []*MsgTraceEgress
   230  	for _, e := range t.Events {
   231  		if e.typ() == MsgTraceEgressType {
   232  			eg = append(eg, getTraceAs[MsgTraceEgress](e))
   233  		}
   234  	}
   235  	return eg
   236  }
   237  
   238  const (
   239  	errMsgTraceOnlyNoSupport   = "Not delivered because remote does not support message tracing"
   240  	errMsgTraceNoSupport       = "Message delivered but remote does not support message tracing so no trace event generated from there"
   241  	errMsgTraceNoEcho          = "Not delivered because of no echo"
   242  	errMsgTracePubViolation    = "Not delivered because publish denied for this subject"
   243  	errMsgTraceSubDeny         = "Not delivered because subscription denies this subject"
   244  	errMsgTraceSubClosed       = "Not delivered because subscription is closed"
   245  	errMsgTraceClientClosed    = "Not delivered because client is closed"
   246  	errMsgTraceAutoSubExceeded = "Not delivered because auto-unsubscribe exceeded"
   247  )
   248  
   249  type msgTrace struct {
   250  	ready int32
   251  	srv   *Server
   252  	acc   *Account
   253  	// Origin account name, set only if acc is nil when acc lookup failed.
   254  	oan   string
   255  	dest  string
   256  	event *MsgTraceEvent
   257  	js    *MsgTraceJetStream
   258  	hop   string
   259  	nhop  string
   260  	tonly bool // Will only trace the message, not do delivery.
   261  	ct    compressionType
   262  }
   263  
   264  // This will be false outside of the tests, so when building the server binary,
   265  // any code where you see `if msgTraceRunInTests` statement will be compiled
   266  // out, so this will have no performance penalty.
   267  var (
   268  	msgTraceRunInTests   bool
   269  	msgTraceCheckSupport bool
   270  )
   271  
   272  // Returns the message trace object, if message is being traced,
   273  // and `true` if we want to only trace, not actually deliver the message.
   274  func (c *client) isMsgTraceEnabled() (*msgTrace, bool) {
   275  	t := c.pa.trace
   276  	if t == nil {
   277  		return nil, false
   278  	}
   279  	return t, t.tonly
   280  }
   281  
   282  // For LEAF/ROUTER/GATEWAY, return false if the remote does not support
   283  // message tracing (important if the tracing requests trace-only).
   284  func (c *client) msgTraceSupport() bool {
   285  	// Exclude client connection from the protocol check.
   286  	return c.kind == CLIENT || c.opts.Protocol >= MsgTraceProto
   287  }
   288  
   289  func getConnName(c *client) string {
   290  	switch c.kind {
   291  	case ROUTER:
   292  		if n := c.route.remoteName; n != _EMPTY_ {
   293  			return n
   294  		}
   295  	case GATEWAY:
   296  		if n := c.gw.remoteName; n != _EMPTY_ {
   297  			return n
   298  		}
   299  	case LEAF:
   300  		if n := c.leaf.remoteServer; n != _EMPTY_ {
   301  			return n
   302  		}
   303  	}
   304  	return c.opts.Name
   305  }
   306  
   307  func getCompressionType(cts string) compressionType {
   308  	if cts == _EMPTY_ {
   309  		return noCompression
   310  	}
   311  	cts = strings.ToLower(cts)
   312  	if strings.Contains(cts, "snappy") || strings.Contains(cts, "s2") {
   313  		return snappyCompression
   314  	}
   315  	if strings.Contains(cts, "gzip") {
   316  		return gzipCompression
   317  	}
   318  	return unsupportedCompression
   319  }
   320  
   321  func (c *client) initMsgTrace() *msgTrace {
   322  	// The code in the "if" statement is only running in test mode.
   323  	if msgTraceRunInTests {
   324  		// Check the type of client that tries to initialize a trace struct.
   325  		if !(c.kind == CLIENT || c.kind == ROUTER || c.kind == GATEWAY || c.kind == LEAF) {
   326  			panic(fmt.Sprintf("Unexpected client type %q trying to initialize msgTrace", c.kindString()))
   327  		}
   328  		// In some tests, we want to make a server behave like an old server
   329  		// and so even if a trace header is received, we want the server to
   330  		// simply ignore it.
   331  		if msgTraceCheckSupport {
   332  			if c.srv == nil || c.srv.getServerProto() < MsgTraceProto {
   333  				return nil
   334  			}
   335  		}
   336  	}
   337  	if c.pa.hdr <= 0 {
   338  		return nil
   339  	}
   340  	hdr := c.msgBuf[:c.pa.hdr]
   341  	headers, external := genHeaderMapIfTraceHeadersPresent(hdr)
   342  	if len(headers) == 0 {
   343  		return nil
   344  	}
   345  	// Little helper to give us the first value of a given header, or _EMPTY_
   346  	// if key is not present.
   347  	getHdrVal := func(key string) string {
   348  		vv, ok := headers[key]
   349  		if !ok {
   350  			return _EMPTY_
   351  		}
   352  		return vv[0]
   353  	}
   354  	ct := getCompressionType(getHdrVal(acceptEncodingHeader))
   355  	var (
   356  		dest      string
   357  		traceOnly bool
   358  	)
   359  	// Check for traceOnly only if not external.
   360  	if !external {
   361  		if to := getHdrVal(MsgTraceOnly); to != _EMPTY_ {
   362  			tos := strings.ToLower(to)
   363  			switch tos {
   364  			case "1", "true", "on":
   365  				traceOnly = true
   366  			}
   367  		}
   368  		dest = getHdrVal(MsgTraceDest)
   369  		// Check the destination to see if this is a valid public subject.
   370  		if !IsValidPublishSubject(dest) {
   371  			// We still have to return a msgTrace object (if traceOnly is set)
   372  			// because if we don't, the message will end-up being delivered to
   373  			// applications, which may break them. We report the error in any case.
   374  			c.Errorf("Destination %q is not valid, won't be able to trace events", dest)
   375  			if !traceOnly {
   376  				// We can bail, tracing will be disabled for this message.
   377  				return nil
   378  			}
   379  		}
   380  	}
   381  	var (
   382  		// Account to use when sending the trace event
   383  		acc *Account
   384  		// Ingress' account name
   385  		ian string
   386  		// Origin account name
   387  		oan string
   388  		// The hop "id", taken from headers only when not from CLIENT
   389  		hop string
   390  	)
   391  	if c.kind == ROUTER || c.kind == GATEWAY || c.kind == LEAF {
   392  		// The ingress account name will always be c.pa.account, but `acc` may
   393  		// be different if we have an origin account header.
   394  		if c.kind == LEAF {
   395  			ian = c.acc.GetName()
   396  		} else {
   397  			ian = string(c.pa.account)
   398  		}
   399  		// The remote will have set the origin account header only if the
   400  		// message changed account (think of service imports).
   401  		oan = getHdrVal(MsgTraceOriginAccount)
   402  		if oan == _EMPTY_ {
   403  			// For LEAF or ROUTER with pinned-account, we can use the c.acc.
   404  			if c.kind == LEAF || (c.kind == ROUTER && len(c.route.accName) > 0) {
   405  				acc = c.acc
   406  			} else {
   407  				// We will lookup account with c.pa.account (or ian).
   408  				oan = ian
   409  			}
   410  		}
   411  		// Unless we already got the account, we need to look it up.
   412  		if acc == nil {
   413  			// We don't want to do account resolving here.
   414  			if acci, ok := c.srv.accounts.Load(oan); ok {
   415  				acc = acci.(*Account)
   416  				// Since we have looked-up the account, we don't need oan, so
   417  				// clear it in case it was set.
   418  				oan = _EMPTY_
   419  			} else {
   420  				// We still have to return a msgTrace object (if traceOnly is set)
   421  				// because if we don't, the message will end-up being delivered to
   422  				// applications, which may break them. We report the error in any case.
   423  				c.Errorf("Account %q was not found, won't be able to trace events", oan)
   424  				if !traceOnly {
   425  					// We can bail, tracing will be disabled for this message.
   426  					return nil
   427  				}
   428  			}
   429  		}
   430  		// Check the hop header
   431  		hop = getHdrVal(MsgTraceHop)
   432  	} else {
   433  		acc = c.acc
   434  		ian = acc.GetName()
   435  	}
   436  	// If external, we need to have the account's trace destination set,
   437  	// otherwise, we are not enabling tracing.
   438  	if external {
   439  		var sampling int
   440  		if acc != nil {
   441  			dest, sampling = acc.getTraceDestAndSampling()
   442  		}
   443  		if dest == _EMPTY_ {
   444  			// No account destination, no tracing for external trace headers.
   445  			return nil
   446  		}
   447  		// Check sampling, but only from origin server.
   448  		if c.kind == CLIENT && !sample(sampling) {
   449  			// Need to desactivate the traceParentHdr so that if the message
   450  			// is routed, it does possibly trigger a trace there.
   451  			disableTraceHeaders(c, hdr)
   452  			return nil
   453  		}
   454  	}
   455  	c.pa.trace = &msgTrace{
   456  		srv:  c.srv,
   457  		acc:  acc,
   458  		oan:  oan,
   459  		dest: dest,
   460  		ct:   ct,
   461  		hop:  hop,
   462  		event: &MsgTraceEvent{
   463  			Request: MsgTraceRequest{
   464  				Header:  headers,
   465  				MsgSize: c.pa.size,
   466  			},
   467  			Events: append(MsgTraceEvents(nil), &MsgTraceIngress{
   468  				MsgTraceBase: MsgTraceBase{
   469  					Type:      MsgTraceIngressType,
   470  					Timestamp: time.Now(),
   471  				},
   472  				Kind:    c.kind,
   473  				CID:     c.cid,
   474  				Name:    getConnName(c),
   475  				Account: ian,
   476  				Subject: string(c.pa.subject),
   477  			}),
   478  		},
   479  		tonly: traceOnly,
   480  	}
   481  	return c.pa.trace
   482  }
   483  
   484  func sample(sampling int) bool {
   485  	// Option parsing should ensure that sampling is [1..100], but consider
   486  	// any value outside of this range to be 100%.
   487  	if sampling <= 0 || sampling >= 100 {
   488  		return true
   489  	}
   490  	return rand.Int31n(100) <= int32(sampling)
   491  }
   492  
   493  // This function will return the header as a map (instead of http.Header because
   494  // we want to preserve the header names' case) and a boolean that indicates if
   495  // the headers have been lifted due to the presence of the external trace header
   496  // only.
   497  // Note that because of the traceParentHdr, the search is done in a case
   498  // insensitive way, but if the header is found, it is rewritten in lower case
   499  // as suggested by the spec, but also to make it easier to disable the header
   500  // when needed.
   501  func genHeaderMapIfTraceHeadersPresent(hdr []byte) (map[string][]string, bool) {
   502  
   503  	var (
   504  		_keys               = [64][]byte{}
   505  		_vals               = [64][]byte{}
   506  		m                   map[string][]string
   507  		traceDestHdrFound   bool
   508  		traceParentHdrFound bool
   509  	)
   510  	// Skip the hdrLine
   511  	if !bytes.HasPrefix(hdr, stringToBytes(hdrLine)) {
   512  		return nil, false
   513  	}
   514  
   515  	traceDestHdrAsBytes := stringToBytes(MsgTraceDest)
   516  	traceParentHdrAsBytes := stringToBytes(traceParentHdr)
   517  	crLFAsBytes := stringToBytes(CR_LF)
   518  	dashAsBytes := stringToBytes("-")
   519  
   520  	keys := _keys[:0]
   521  	vals := _vals[:0]
   522  
   523  	for i := len(hdrLine); i < len(hdr); {
   524  		// Search for key/val delimiter
   525  		del := bytes.IndexByte(hdr[i:], ':')
   526  		if del < 0 {
   527  			break
   528  		}
   529  		keyStart := i
   530  		key := hdr[keyStart : keyStart+del]
   531  		i += del + 1
   532  		valStart := i
   533  		nl := bytes.Index(hdr[valStart:], crLFAsBytes)
   534  		if nl < 0 {
   535  			break
   536  		}
   537  		if len(key) > 0 {
   538  			val := bytes.Trim(hdr[valStart:valStart+nl], " \t")
   539  			vals = append(vals, val)
   540  
   541  			// Check for the external trace header.
   542  			if bytes.EqualFold(key, traceParentHdrAsBytes) {
   543  				// Rewrite the header using lower case if needed.
   544  				if !bytes.Equal(key, traceParentHdrAsBytes) {
   545  					copy(hdr[keyStart:], traceParentHdrAsBytes)
   546  				}
   547  				// We will now check if the value has sampling or not.
   548  				// TODO(ik): Not sure if this header can have multiple values
   549  				// or not, and if so, what would be the rule to check for
   550  				// sampling. What is done here is to check them all until we
   551  				// found one with sampling.
   552  				if !traceParentHdrFound {
   553  					tk := bytes.Split(val, dashAsBytes)
   554  					if len(tk) == 4 && len([]byte(tk[3])) == 2 {
   555  						if hexVal, err := strconv.ParseInt(bytesToString(tk[3]), 16, 8); err == nil {
   556  							if hexVal&0x1 == 0x1 {
   557  								traceParentHdrFound = true
   558  							}
   559  						}
   560  					}
   561  				}
   562  				// Add to the keys with the external trace header in lower case.
   563  				keys = append(keys, traceParentHdrAsBytes)
   564  			} else {
   565  				// Is the key the Nats-Trace-Dest header?
   566  				if bytes.EqualFold(key, traceDestHdrAsBytes) {
   567  					traceDestHdrFound = true
   568  				}
   569  				// Add to the keys and preserve the key's case
   570  				keys = append(keys, key)
   571  			}
   572  		}
   573  		i += nl + 2
   574  	}
   575  	if !traceDestHdrFound && !traceParentHdrFound {
   576  		return nil, false
   577  	}
   578  	m = make(map[string][]string, len(keys))
   579  	for i, k := range keys {
   580  		hname := string(k)
   581  		m[hname] = append(m[hname], string(vals[i]))
   582  	}
   583  	return m, !traceDestHdrFound && traceParentHdrFound
   584  }
   585  
   586  // Special case where we create a trace event before parsing the message.
   587  // This is for cases where the connection will be closed when detecting
   588  // an error during early message processing (for instance max payload).
   589  func (c *client) initAndSendIngressErrEvent(hdr []byte, dest string, ingressError error) {
   590  	if ingressError == nil {
   591  		return
   592  	}
   593  	ct := getAcceptEncoding(hdr)
   594  	t := &msgTrace{
   595  		srv:  c.srv,
   596  		acc:  c.acc,
   597  		dest: dest,
   598  		ct:   ct,
   599  		event: &MsgTraceEvent{
   600  			Request: MsgTraceRequest{MsgSize: c.pa.size},
   601  			Events: append(MsgTraceEvents(nil), &MsgTraceIngress{
   602  				MsgTraceBase: MsgTraceBase{
   603  					Type:      MsgTraceIngressType,
   604  					Timestamp: time.Now(),
   605  				},
   606  				Kind:  c.kind,
   607  				CID:   c.cid,
   608  				Name:  getConnName(c),
   609  				Error: ingressError.Error(),
   610  			}),
   611  		},
   612  	}
   613  	t.sendEvent()
   614  }
   615  
   616  // Returns `true` if message tracing is enabled and we are tracing only,
   617  // that is, we are not going to deliver the inbound message, returns
   618  // `false` otherwise (no tracing, or tracing and message delivery).
   619  func (t *msgTrace) traceOnly() bool {
   620  	return t != nil && t.tonly
   621  }
   622  
   623  func (t *msgTrace) setOriginAccountHeaderIfNeeded(c *client, acc *Account, msg []byte) []byte {
   624  	var oan string
   625  	// If t.acc is set, only check that, not t.oan.
   626  	if t.acc != nil {
   627  		if t.acc != acc {
   628  			oan = t.acc.GetName()
   629  		}
   630  	} else if t.oan != acc.GetName() {
   631  		oan = t.oan
   632  	}
   633  	if oan != _EMPTY_ {
   634  		msg = c.setHeader(MsgTraceOriginAccount, oan, msg)
   635  	}
   636  	return msg
   637  }
   638  
   639  func (t *msgTrace) setHopHeader(c *client, msg []byte) []byte {
   640  	e := t.event
   641  	e.Hops++
   642  	if len(t.hop) > 0 {
   643  		t.nhop = fmt.Sprintf("%s.%d", t.hop, e.Hops)
   644  	} else {
   645  		t.nhop = fmt.Sprintf("%d", e.Hops)
   646  	}
   647  	return c.setHeader(MsgTraceHop, t.nhop, msg)
   648  }
   649  
   650  // Will look for the MsgTraceSendTo and traceParentHdr headers and change the first
   651  // character to an 'X' so that if this message is sent to a remote, the remote
   652  // will not initialize tracing since it won't find the actual trace headers.
   653  // The function returns the position of the headers so it can efficiently be
   654  // re-enabled by calling enableTraceHeaders.
   655  // Note that if `msg` can be either the header alone or the full message
   656  // (header and payload). This function will use c.pa.hdr to limit the
   657  // search to the header section alone.
   658  func disableTraceHeaders(c *client, msg []byte) []int {
   659  	// Code largely copied from getHeader(), except that we don't need the value
   660  	if c.pa.hdr <= 0 {
   661  		return []int{-1, -1}
   662  	}
   663  	hdr := msg[:c.pa.hdr]
   664  	headers := [2]string{MsgTraceDest, traceParentHdr}
   665  	positions := [2]int{-1, -1}
   666  	for i := 0; i < 2; i++ {
   667  		key := stringToBytes(headers[i])
   668  		pos := bytes.Index(hdr, key)
   669  		if pos < 0 {
   670  			continue
   671  		}
   672  		// Make sure this key does not have additional prefix.
   673  		if pos < 2 || hdr[pos-1] != '\n' || hdr[pos-2] != '\r' {
   674  			continue
   675  		}
   676  		index := pos + len(key)
   677  		if index >= len(hdr) {
   678  			continue
   679  		}
   680  		if hdr[index] != ':' {
   681  			continue
   682  		}
   683  		// Disable the trace by altering the first character of the header
   684  		hdr[pos] = 'X'
   685  		positions[i] = pos
   686  	}
   687  	// Return the positions of those characters so we can re-enable the headers.
   688  	return positions[:2]
   689  }
   690  
   691  // Changes back the character at the given position `pos` in the `msg`
   692  // byte slice to the first character of the MsgTraceSendTo header.
   693  func enableTraceHeaders(c *client, msg []byte, positions []int) {
   694  	firstChar := [2]byte{MsgTraceDest[0], traceParentHdr[0]}
   695  	for i, pos := range positions {
   696  		if pos == -1 {
   697  			continue
   698  		}
   699  		msg[pos] = firstChar[i]
   700  	}
   701  }
   702  
   703  func (t *msgTrace) setIngressError(err string) {
   704  	if i := t.event.Ingress(); i != nil {
   705  		i.Error = err
   706  	}
   707  }
   708  
   709  func (t *msgTrace) addSubjectMappingEvent(subj []byte) {
   710  	if t == nil {
   711  		return
   712  	}
   713  	t.event.Events = append(t.event.Events, &MsgTraceSubjectMapping{
   714  		MsgTraceBase: MsgTraceBase{
   715  			Type:      MsgTraceSubjectMappingType,
   716  			Timestamp: time.Now(),
   717  		},
   718  		MappedTo: string(subj),
   719  	})
   720  }
   721  
   722  func (t *msgTrace) addEgressEvent(dc *client, sub *subscription, err string) {
   723  	if t == nil {
   724  		return
   725  	}
   726  	e := &MsgTraceEgress{
   727  		MsgTraceBase: MsgTraceBase{
   728  			Type:      MsgTraceEgressType,
   729  			Timestamp: time.Now(),
   730  		},
   731  		Kind:  dc.kind,
   732  		CID:   dc.cid,
   733  		Name:  getConnName(dc),
   734  		Hop:   t.nhop,
   735  		Error: err,
   736  	}
   737  	t.nhop = _EMPTY_
   738  	// Specific to CLIENT connections...
   739  	if dc.kind == CLIENT {
   740  		// Set the subscription's subject and possibly queue name.
   741  		e.Subscription = string(sub.subject)
   742  		if len(sub.queue) > 0 {
   743  			e.Queue = string(sub.queue)
   744  		}
   745  	}
   746  	if dc.kind == CLIENT || dc.kind == LEAF {
   747  		if i := t.event.Ingress(); i != nil {
   748  			// If the Ingress' account is different from the destination's
   749  			// account, add the account name into the Egress trace event.
   750  			// This would happen with service imports.
   751  			if dcAccName := dc.acc.GetName(); dcAccName != i.Account {
   752  				e.Account = dcAccName
   753  			}
   754  		}
   755  	}
   756  	t.event.Events = append(t.event.Events, e)
   757  }
   758  
   759  func (t *msgTrace) addStreamExportEvent(dc *client, to []byte) {
   760  	if t == nil {
   761  		return
   762  	}
   763  	dc.mu.Lock()
   764  	accName := dc.acc.GetName()
   765  	dc.mu.Unlock()
   766  	t.event.Events = append(t.event.Events, &MsgTraceStreamExport{
   767  		MsgTraceBase: MsgTraceBase{
   768  			Type:      MsgTraceStreamExportType,
   769  			Timestamp: time.Now(),
   770  		},
   771  		Account: accName,
   772  		To:      string(to),
   773  	})
   774  }
   775  
   776  func (t *msgTrace) addServiceImportEvent(accName, from, to string) {
   777  	if t == nil {
   778  		return
   779  	}
   780  	t.event.Events = append(t.event.Events, &MsgTraceServiceImport{
   781  		MsgTraceBase: MsgTraceBase{
   782  			Type:      MsgTraceServiceImportType,
   783  			Timestamp: time.Now(),
   784  		},
   785  		Account: accName,
   786  		From:    from,
   787  		To:      to,
   788  	})
   789  }
   790  
   791  func (t *msgTrace) addJetStreamEvent(streamName string) {
   792  	if t == nil {
   793  		return
   794  	}
   795  	t.js = &MsgTraceJetStream{
   796  		MsgTraceBase: MsgTraceBase{
   797  			Type:      MsgTraceJetStreamType,
   798  			Timestamp: time.Now(),
   799  		},
   800  		Stream: streamName,
   801  	}
   802  	t.event.Events = append(t.event.Events, t.js)
   803  }
   804  
   805  func (t *msgTrace) updateJetStreamEvent(subject string, noInterest bool) {
   806  	if t == nil {
   807  		return
   808  	}
   809  	// JetStream event should have been created in addJetStreamEvent
   810  	if t.js == nil {
   811  		return
   812  	}
   813  	t.js.Subject = subject
   814  	t.js.NoInterest = noInterest
   815  	// Update the timestamp since this is more accurate than when it
   816  	// was first added in addJetStreamEvent().
   817  	t.js.Timestamp = time.Now()
   818  }
   819  
   820  func (t *msgTrace) sendEventFromJetStream(err error) {
   821  	if t == nil {
   822  		return
   823  	}
   824  	// JetStream event should have been created in addJetStreamEvent
   825  	if t.js == nil {
   826  		return
   827  	}
   828  	if err != nil {
   829  		t.js.Error = err.Error()
   830  	}
   831  	t.sendEvent()
   832  }
   833  
   834  func (t *msgTrace) sendEvent() {
   835  	if t == nil {
   836  		return
   837  	}
   838  	if t.js != nil {
   839  		ready := atomic.AddInt32(&t.ready, 1) == 2
   840  		if !ready {
   841  			return
   842  		}
   843  	}
   844  	t.srv.sendInternalAccountSysMsg(t.acc, t.dest, &t.event.Server, t.event, t.ct)
   845  }