github.com/v2fly/tools@v0.100.0/internal/event/core/export.go (about) 1 // Copyright 2019 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package core 6 7 import ( 8 "context" 9 "sync/atomic" 10 "time" 11 "unsafe" 12 13 "github.com/v2fly/tools/internal/event/label" 14 ) 15 16 // Exporter is a function that handles events. 17 // It may return a modified context and event. 18 type Exporter func(context.Context, Event, label.Map) context.Context 19 20 var ( 21 exporter unsafe.Pointer 22 ) 23 24 // SetExporter sets the global exporter function that handles all events. 25 // The exporter is called synchronously from the event call site, so it should 26 // return quickly so as not to hold up user code. 27 func SetExporter(e Exporter) { 28 p := unsafe.Pointer(&e) 29 if e == nil { 30 // &e is always valid, and so p is always valid, but for the early abort 31 // of ProcessEvent to be efficient it needs to make the nil check on the 32 // pointer without having to dereference it, so we make the nil function 33 // also a nil pointer 34 p = nil 35 } 36 atomic.StorePointer(&exporter, p) 37 } 38 39 // deliver is called to deliver an event to the supplied exporter. 40 // it will fill in the time. 41 func deliver(ctx context.Context, exporter Exporter, ev Event) context.Context { 42 // add the current time to the event 43 ev.at = time.Now() 44 // hand the event off to the current exporter 45 return exporter(ctx, ev, ev) 46 } 47 48 // Export is called to deliver an event to the global exporter if set. 49 func Export(ctx context.Context, ev Event) context.Context { 50 // get the global exporter and abort early if there is not one 51 exporterPtr := (*Exporter)(atomic.LoadPointer(&exporter)) 52 if exporterPtr == nil { 53 return ctx 54 } 55 return deliver(ctx, *exporterPtr, ev) 56 } 57 58 // ExportPair is called to deliver a start event to the supplied exporter. 59 // It also returns a function that will deliver the end event to the same 60 // exporter. 61 // It will fill in the time. 62 func ExportPair(ctx context.Context, begin, end Event) (context.Context, func()) { 63 // get the global exporter and abort early if there is not one 64 exporterPtr := (*Exporter)(atomic.LoadPointer(&exporter)) 65 if exporterPtr == nil { 66 return ctx, func() {} 67 } 68 ctx = deliver(ctx, *exporterPtr, begin) 69 return ctx, func() { deliver(ctx, *exporterPtr, end) } 70 }