func (txn *txn) End() error { txn.Lock() defer txn.Unlock() if txn.finished { return errAlreadyEnded } txn.finished = true r := recover() if nil != r { e := internal.TxnErrorFromPanic(time.Now(), r) e.Stack = internal.GetStackTrace(0) txn.noticeErrorInternal(e) } txn.stop = time.Now() txn.duration = txn.stop.Sub(txn.start) txn.freezeName() // Assign apdexThreshold regardless of whether or not the transaction // gets apdex since it may be used to calculate the trace threshold. txn.apdexThreshold = internal.CalculateApdexThreshold(txn.Reply, txn.finalName) if txn.getsApdex() { if txn.hasErrors() { txn.zone = internal.ApdexFailing } else { txn.zone = internal.CalculateApdexZone(txn.apdexThreshold, txn.duration) } } else { txn.zone = internal.ApdexNone } if txn.Config.Logger.DebugEnabled() { txn.Config.Logger.Debug("transaction ended", map[string]interface{}{ "name": txn.finalName, "duration_ms": txn.duration.Seconds() * 1000.0, "ignored": txn.ignore, "run": txn.Reply.RunID, }) } if !txn.ignore { txn.Consumer.Consume(txn.Reply.RunID, txn) } // Note that if a consumer uses `panic(nil)`, the panic will not // propagate. if nil != r { panic(r) } return nil }
func (txn *txn) NoticeError(err error) error { txn.Lock() defer txn.Unlock() if txn.finished { return errAlreadyEnded } if nil == err { return errNilError } e := internal.TxnErrorFromError(time.Now(), err) e.Stack = internal.GetStackTrace(2) return txn.noticeErrorInternal(e) }
func headersJustWritten(txn *txn, code int) { if txn.finished { return } if txn.wroteHeader { return } txn.wroteHeader = true internal.ResponseHeaderAttributes(txn.attrs, txn.W.Header()) internal.ResponseCodeAttribute(txn.attrs, code) if responseCodeIsError(&txn.Config, code) { e := internal.TxnErrorFromResponseCode(time.Now(), code) e.Stack = internal.GetStackTrace(1) txn.noticeErrorInternal(e) } }