fieldopt.go 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520
  1. //go:build windows
  2. // +build windows
  3. package etw
  4. import (
  5. "fmt"
  6. "math"
  7. "reflect"
  8. "syscall"
  9. "time"
  10. "unsafe"
  11. )
  12. // FieldOpt defines the option function type that can be passed to
  13. // Provider.WriteEvent to add fields to the event.
  14. type FieldOpt func(em *eventMetadata, ed *eventData)
  15. // WithFields returns the variadic arguments as a single slice.
  16. func WithFields(opts ...FieldOpt) []FieldOpt {
  17. return opts
  18. }
  19. // BoolField adds a single bool field to the event.
  20. func BoolField(name string, value bool) FieldOpt {
  21. return func(em *eventMetadata, ed *eventData) {
  22. em.writeField(name, inTypeUint8, outTypeBoolean, 0)
  23. bool8 := uint8(0)
  24. if value {
  25. bool8 = uint8(1)
  26. }
  27. ed.writeUint8(bool8)
  28. }
  29. }
  30. // BoolArray adds an array of bool to the event.
  31. func BoolArray(name string, values []bool) FieldOpt {
  32. return func(em *eventMetadata, ed *eventData) {
  33. em.writeArray(name, inTypeUint8, outTypeBoolean, 0)
  34. ed.writeUint16(uint16(len(values)))
  35. for _, v := range values {
  36. bool8 := uint8(0)
  37. if v {
  38. bool8 = uint8(1)
  39. }
  40. ed.writeUint8(bool8)
  41. }
  42. }
  43. }
  44. // StringField adds a single string field to the event.
  45. func StringField(name string, value string) FieldOpt {
  46. return func(em *eventMetadata, ed *eventData) {
  47. em.writeField(name, inTypeANSIString, outTypeUTF8, 0)
  48. ed.writeString(value)
  49. }
  50. }
  51. // StringArray adds an array of string to the event.
  52. func StringArray(name string, values []string) FieldOpt {
  53. return func(em *eventMetadata, ed *eventData) {
  54. em.writeArray(name, inTypeANSIString, outTypeUTF8, 0)
  55. ed.writeUint16(uint16(len(values)))
  56. for _, v := range values {
  57. ed.writeString(v)
  58. }
  59. }
  60. }
  61. // IntField adds a single int field to the event.
  62. func IntField(name string, value int) FieldOpt {
  63. switch unsafe.Sizeof(value) {
  64. case 4:
  65. return Int32Field(name, int32(value))
  66. case 8:
  67. return Int64Field(name, int64(value))
  68. default:
  69. panic("Unsupported int size")
  70. }
  71. }
  72. // IntArray adds an array of int to the event.
  73. func IntArray(name string, values []int) FieldOpt {
  74. inType := inTypeNull
  75. var writeItem func(*eventData, int)
  76. switch unsafe.Sizeof(values[0]) {
  77. case 4:
  78. inType = inTypeInt32
  79. writeItem = func(ed *eventData, item int) { ed.writeInt32(int32(item)) }
  80. case 8:
  81. inType = inTypeInt64
  82. writeItem = func(ed *eventData, item int) { ed.writeInt64(int64(item)) }
  83. default:
  84. panic("Unsupported int size")
  85. }
  86. return func(em *eventMetadata, ed *eventData) {
  87. em.writeArray(name, inType, outTypeDefault, 0)
  88. ed.writeUint16(uint16(len(values)))
  89. for _, v := range values {
  90. writeItem(ed, v)
  91. }
  92. }
  93. }
  94. // Int8Field adds a single int8 field to the event.
  95. func Int8Field(name string, value int8) FieldOpt {
  96. return func(em *eventMetadata, ed *eventData) {
  97. em.writeField(name, inTypeInt8, outTypeDefault, 0)
  98. ed.writeInt8(value)
  99. }
  100. }
  101. // Int8Array adds an array of int8 to the event.
  102. func Int8Array(name string, values []int8) FieldOpt {
  103. return func(em *eventMetadata, ed *eventData) {
  104. em.writeArray(name, inTypeInt8, outTypeDefault, 0)
  105. ed.writeUint16(uint16(len(values)))
  106. for _, v := range values {
  107. ed.writeInt8(v)
  108. }
  109. }
  110. }
  111. // Int16Field adds a single int16 field to the event.
  112. func Int16Field(name string, value int16) FieldOpt {
  113. return func(em *eventMetadata, ed *eventData) {
  114. em.writeField(name, inTypeInt16, outTypeDefault, 0)
  115. ed.writeInt16(value)
  116. }
  117. }
  118. // Int16Array adds an array of int16 to the event.
  119. func Int16Array(name string, values []int16) FieldOpt {
  120. return func(em *eventMetadata, ed *eventData) {
  121. em.writeArray(name, inTypeInt16, outTypeDefault, 0)
  122. ed.writeUint16(uint16(len(values)))
  123. for _, v := range values {
  124. ed.writeInt16(v)
  125. }
  126. }
  127. }
  128. // Int32Field adds a single int32 field to the event.
  129. func Int32Field(name string, value int32) FieldOpt {
  130. return func(em *eventMetadata, ed *eventData) {
  131. em.writeField(name, inTypeInt32, outTypeDefault, 0)
  132. ed.writeInt32(value)
  133. }
  134. }
  135. // Int32Array adds an array of int32 to the event.
  136. func Int32Array(name string, values []int32) FieldOpt {
  137. return func(em *eventMetadata, ed *eventData) {
  138. em.writeArray(name, inTypeInt32, outTypeDefault, 0)
  139. ed.writeUint16(uint16(len(values)))
  140. for _, v := range values {
  141. ed.writeInt32(v)
  142. }
  143. }
  144. }
  145. // Int64Field adds a single int64 field to the event.
  146. func Int64Field(name string, value int64) FieldOpt {
  147. return func(em *eventMetadata, ed *eventData) {
  148. em.writeField(name, inTypeInt64, outTypeDefault, 0)
  149. ed.writeInt64(value)
  150. }
  151. }
  152. // Int64Array adds an array of int64 to the event.
  153. func Int64Array(name string, values []int64) FieldOpt {
  154. return func(em *eventMetadata, ed *eventData) {
  155. em.writeArray(name, inTypeInt64, outTypeDefault, 0)
  156. ed.writeUint16(uint16(len(values)))
  157. for _, v := range values {
  158. ed.writeInt64(v)
  159. }
  160. }
  161. }
  162. // UintField adds a single uint field to the event.
  163. func UintField(name string, value uint) FieldOpt {
  164. switch unsafe.Sizeof(value) {
  165. case 4:
  166. return Uint32Field(name, uint32(value))
  167. case 8:
  168. return Uint64Field(name, uint64(value))
  169. default:
  170. panic("Unsupported uint size")
  171. }
  172. }
  173. // UintArray adds an array of uint to the event.
  174. func UintArray(name string, values []uint) FieldOpt {
  175. inType := inTypeNull
  176. var writeItem func(*eventData, uint)
  177. switch unsafe.Sizeof(values[0]) {
  178. case 4:
  179. inType = inTypeUint32
  180. writeItem = func(ed *eventData, item uint) { ed.writeUint32(uint32(item)) }
  181. case 8:
  182. inType = inTypeUint64
  183. writeItem = func(ed *eventData, item uint) { ed.writeUint64(uint64(item)) }
  184. default:
  185. panic("Unsupported uint size")
  186. }
  187. return func(em *eventMetadata, ed *eventData) {
  188. em.writeArray(name, inType, outTypeDefault, 0)
  189. ed.writeUint16(uint16(len(values)))
  190. for _, v := range values {
  191. writeItem(ed, v)
  192. }
  193. }
  194. }
  195. // Uint8Field adds a single uint8 field to the event.
  196. func Uint8Field(name string, value uint8) FieldOpt {
  197. return func(em *eventMetadata, ed *eventData) {
  198. em.writeField(name, inTypeUint8, outTypeDefault, 0)
  199. ed.writeUint8(value)
  200. }
  201. }
  202. // Uint8Array adds an array of uint8 to the event.
  203. func Uint8Array(name string, values []uint8) FieldOpt {
  204. return func(em *eventMetadata, ed *eventData) {
  205. em.writeArray(name, inTypeUint8, outTypeDefault, 0)
  206. ed.writeUint16(uint16(len(values)))
  207. for _, v := range values {
  208. ed.writeUint8(v)
  209. }
  210. }
  211. }
  212. // Uint16Field adds a single uint16 field to the event.
  213. func Uint16Field(name string, value uint16) FieldOpt {
  214. return func(em *eventMetadata, ed *eventData) {
  215. em.writeField(name, inTypeUint16, outTypeDefault, 0)
  216. ed.writeUint16(value)
  217. }
  218. }
  219. // Uint16Array adds an array of uint16 to the event.
  220. func Uint16Array(name string, values []uint16) FieldOpt {
  221. return func(em *eventMetadata, ed *eventData) {
  222. em.writeArray(name, inTypeUint16, outTypeDefault, 0)
  223. ed.writeUint16(uint16(len(values)))
  224. for _, v := range values {
  225. ed.writeUint16(v)
  226. }
  227. }
  228. }
  229. // Uint32Field adds a single uint32 field to the event.
  230. func Uint32Field(name string, value uint32) FieldOpt {
  231. return func(em *eventMetadata, ed *eventData) {
  232. em.writeField(name, inTypeUint32, outTypeDefault, 0)
  233. ed.writeUint32(value)
  234. }
  235. }
  236. // Uint32Array adds an array of uint32 to the event.
  237. func Uint32Array(name string, values []uint32) FieldOpt {
  238. return func(em *eventMetadata, ed *eventData) {
  239. em.writeArray(name, inTypeUint32, outTypeDefault, 0)
  240. ed.writeUint16(uint16(len(values)))
  241. for _, v := range values {
  242. ed.writeUint32(v)
  243. }
  244. }
  245. }
  246. // Uint64Field adds a single uint64 field to the event.
  247. func Uint64Field(name string, value uint64) FieldOpt {
  248. return func(em *eventMetadata, ed *eventData) {
  249. em.writeField(name, inTypeUint64, outTypeDefault, 0)
  250. ed.writeUint64(value)
  251. }
  252. }
  253. // Uint64Array adds an array of uint64 to the event.
  254. func Uint64Array(name string, values []uint64) FieldOpt {
  255. return func(em *eventMetadata, ed *eventData) {
  256. em.writeArray(name, inTypeUint64, outTypeDefault, 0)
  257. ed.writeUint16(uint16(len(values)))
  258. for _, v := range values {
  259. ed.writeUint64(v)
  260. }
  261. }
  262. }
  263. // UintptrField adds a single uintptr field to the event.
  264. func UintptrField(name string, value uintptr) FieldOpt {
  265. inType := inTypeNull
  266. var writeItem func(*eventData, uintptr)
  267. switch unsafe.Sizeof(value) {
  268. case 4:
  269. inType = inTypeHexInt32
  270. writeItem = func(ed *eventData, item uintptr) { ed.writeUint32(uint32(item)) }
  271. case 8:
  272. inType = inTypeHexInt64
  273. writeItem = func(ed *eventData, item uintptr) { ed.writeUint64(uint64(item)) }
  274. default:
  275. panic("Unsupported uintptr size")
  276. }
  277. return func(em *eventMetadata, ed *eventData) {
  278. em.writeField(name, inType, outTypeDefault, 0)
  279. writeItem(ed, value)
  280. }
  281. }
  282. // UintptrArray adds an array of uintptr to the event.
  283. func UintptrArray(name string, values []uintptr) FieldOpt {
  284. inType := inTypeNull
  285. var writeItem func(*eventData, uintptr)
  286. switch unsafe.Sizeof(values[0]) {
  287. case 4:
  288. inType = inTypeHexInt32
  289. writeItem = func(ed *eventData, item uintptr) { ed.writeUint32(uint32(item)) }
  290. case 8:
  291. inType = inTypeHexInt64
  292. writeItem = func(ed *eventData, item uintptr) { ed.writeUint64(uint64(item)) }
  293. default:
  294. panic("Unsupported uintptr size")
  295. }
  296. return func(em *eventMetadata, ed *eventData) {
  297. em.writeArray(name, inType, outTypeDefault, 0)
  298. ed.writeUint16(uint16(len(values)))
  299. for _, v := range values {
  300. writeItem(ed, v)
  301. }
  302. }
  303. }
  304. // Float32Field adds a single float32 field to the event.
  305. func Float32Field(name string, value float32) FieldOpt {
  306. return func(em *eventMetadata, ed *eventData) {
  307. em.writeField(name, inTypeFloat, outTypeDefault, 0)
  308. ed.writeUint32(math.Float32bits(value))
  309. }
  310. }
  311. // Float32Array adds an array of float32 to the event.
  312. func Float32Array(name string, values []float32) FieldOpt {
  313. return func(em *eventMetadata, ed *eventData) {
  314. em.writeArray(name, inTypeFloat, outTypeDefault, 0)
  315. ed.writeUint16(uint16(len(values)))
  316. for _, v := range values {
  317. ed.writeUint32(math.Float32bits(v))
  318. }
  319. }
  320. }
  321. // Float64Field adds a single float64 field to the event.
  322. func Float64Field(name string, value float64) FieldOpt {
  323. return func(em *eventMetadata, ed *eventData) {
  324. em.writeField(name, inTypeDouble, outTypeDefault, 0)
  325. ed.writeUint64(math.Float64bits(value))
  326. }
  327. }
  328. // Float64Array adds an array of float64 to the event.
  329. func Float64Array(name string, values []float64) FieldOpt {
  330. return func(em *eventMetadata, ed *eventData) {
  331. em.writeArray(name, inTypeDouble, outTypeDefault, 0)
  332. ed.writeUint16(uint16(len(values)))
  333. for _, v := range values {
  334. ed.writeUint64(math.Float64bits(v))
  335. }
  336. }
  337. }
  338. // Struct adds a nested struct to the event, the FieldOpts in the opts argument
  339. // are used to specify the fields of the struct.
  340. func Struct(name string, opts ...FieldOpt) FieldOpt {
  341. return func(em *eventMetadata, ed *eventData) {
  342. em.writeStruct(name, uint8(len(opts)), 0)
  343. for _, opt := range opts {
  344. opt(em, ed)
  345. }
  346. }
  347. }
  348. // Time adds a time to the event.
  349. func Time(name string, value time.Time) FieldOpt {
  350. return func(em *eventMetadata, ed *eventData) {
  351. em.writeField(name, inTypeFileTime, outTypeDateTimeUTC, 0)
  352. ed.writeFiletime(syscall.NsecToFiletime(value.UTC().UnixNano()))
  353. }
  354. }
  355. // Currently, we support logging basic builtin types (int, string, etc), slices
  356. // of basic builtin types, error, types derived from the basic types (e.g. "type
  357. // foo int"), and structs (recursively logging their fields). We do not support
  358. // slices of derived types (e.g. "[]foo").
  359. //
  360. // For types that we don't support, the value is formatted via fmt.Sprint, and
  361. // we also log a message that the type is unsupported along with the formatted
  362. // type. The intent of this is to make it easier to see which types are not
  363. // supported in traces, so we can evaluate adding support for more types in the
  364. // future.
  365. func SmartField(name string, v interface{}) FieldOpt {
  366. switch v := v.(type) {
  367. case bool:
  368. return BoolField(name, v)
  369. case []bool:
  370. return BoolArray(name, v)
  371. case string:
  372. return StringField(name, v)
  373. case []string:
  374. return StringArray(name, v)
  375. case int:
  376. return IntField(name, v)
  377. case []int:
  378. return IntArray(name, v)
  379. case int8:
  380. return Int8Field(name, v)
  381. case []int8:
  382. return Int8Array(name, v)
  383. case int16:
  384. return Int16Field(name, v)
  385. case []int16:
  386. return Int16Array(name, v)
  387. case int32:
  388. return Int32Field(name, v)
  389. case []int32:
  390. return Int32Array(name, v)
  391. case int64:
  392. return Int64Field(name, v)
  393. case []int64:
  394. return Int64Array(name, v)
  395. case uint:
  396. return UintField(name, v)
  397. case []uint:
  398. return UintArray(name, v)
  399. case uint8:
  400. return Uint8Field(name, v)
  401. case []uint8:
  402. return Uint8Array(name, v)
  403. case uint16:
  404. return Uint16Field(name, v)
  405. case []uint16:
  406. return Uint16Array(name, v)
  407. case uint32:
  408. return Uint32Field(name, v)
  409. case []uint32:
  410. return Uint32Array(name, v)
  411. case uint64:
  412. return Uint64Field(name, v)
  413. case []uint64:
  414. return Uint64Array(name, v)
  415. case uintptr:
  416. return UintptrField(name, v)
  417. case []uintptr:
  418. return UintptrArray(name, v)
  419. case float32:
  420. return Float32Field(name, v)
  421. case []float32:
  422. return Float32Array(name, v)
  423. case float64:
  424. return Float64Field(name, v)
  425. case []float64:
  426. return Float64Array(name, v)
  427. case error:
  428. return StringField(name, v.Error())
  429. case time.Time:
  430. return Time(name, v)
  431. default:
  432. switch rv := reflect.ValueOf(v); rv.Kind() {
  433. case reflect.Bool:
  434. return SmartField(name, rv.Bool())
  435. case reflect.Int:
  436. return SmartField(name, int(rv.Int()))
  437. case reflect.Int8:
  438. return SmartField(name, int8(rv.Int()))
  439. case reflect.Int16:
  440. return SmartField(name, int16(rv.Int()))
  441. case reflect.Int32:
  442. return SmartField(name, int32(rv.Int()))
  443. case reflect.Int64:
  444. return SmartField(name, int64(rv.Int())) //nolint:unconvert // make look consistent
  445. case reflect.Uint:
  446. return SmartField(name, uint(rv.Uint()))
  447. case reflect.Uint8:
  448. return SmartField(name, uint8(rv.Uint()))
  449. case reflect.Uint16:
  450. return SmartField(name, uint16(rv.Uint()))
  451. case reflect.Uint32:
  452. return SmartField(name, uint32(rv.Uint()))
  453. case reflect.Uint64:
  454. return SmartField(name, uint64(rv.Uint())) //nolint:unconvert // make look consistent
  455. case reflect.Uintptr:
  456. return SmartField(name, uintptr(rv.Uint()))
  457. case reflect.Float32:
  458. return SmartField(name, float32(rv.Float()))
  459. case reflect.Float64:
  460. return SmartField(name, float64(rv.Float())) //nolint:unconvert // make look consistent
  461. case reflect.String:
  462. return SmartField(name, rv.String())
  463. case reflect.Struct:
  464. fields := make([]FieldOpt, 0, rv.NumField())
  465. for i := 0; i < rv.NumField(); i++ {
  466. field := rv.Field(i)
  467. if field.CanInterface() {
  468. fields = append(fields, SmartField(name, field.Interface()))
  469. }
  470. }
  471. return Struct(name, fields...)
  472. case reflect.Array, reflect.Chan, reflect.Complex128, reflect.Complex64,
  473. reflect.Func, reflect.Interface, reflect.Invalid, reflect.Map, reflect.Ptr,
  474. reflect.Slice, reflect.UnsafePointer:
  475. }
  476. }
  477. return StringField(name, fmt.Sprintf("(Unsupported: %T) %v", v, v))
  478. }