debug.go 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124
  1. /*
  2. * ECAL
  3. *
  4. * Copyright 2020 Matthias Ladkau. All rights reserved.
  5. *
  6. * This Source Code Form is subject to the terms of the MIT
  7. * License, If a copy of the MIT License was not distributed with this
  8. * file, You can obtain one at https://opensource.org/licenses/MIT.
  9. */
  10. package engine
  11. import (
  12. "fmt"
  13. "io"
  14. "os"
  15. "regexp"
  16. "strings"
  17. "sync"
  18. "devt.de/krotik/common/stringutil"
  19. )
  20. /*
  21. EventTracer is a debugging interface to the engine
  22. */
  23. var EventTracer = &eventTrace{lock: &sync.Mutex{}, out: os.Stdout}
  24. /*
  25. eventTrace handles low-level event tracing for debugging purposes
  26. */
  27. type eventTrace struct {
  28. lock *sync.Mutex
  29. eventTraceKind []string
  30. eventTraceState []map[interface{}]interface{}
  31. out io.Writer
  32. }
  33. /*
  34. MonitorEvent adds a request to monitor certain events. The events to monitor
  35. should match the given kind and have the given state values (nil values match
  36. only on the key).
  37. */
  38. func (et *eventTrace) MonitorEvent(kind string, state map[interface{}]interface{}) {
  39. et.lock.Lock()
  40. defer et.lock.Unlock()
  41. et.eventTraceKind = append(et.eventTraceKind, kind)
  42. et.eventTraceState = append(et.eventTraceState, state)
  43. }
  44. /*
  45. Reset removes all added monitoring requests.
  46. */
  47. func (et *eventTrace) Reset() {
  48. et.lock.Lock()
  49. defer et.lock.Unlock()
  50. et.eventTraceKind = nil
  51. et.eventTraceState = nil
  52. }
  53. /*
  54. record records an event action.
  55. */
  56. func (et *eventTrace) record(which *Event, where string, what ...interface{}) {
  57. et.lock.Lock()
  58. defer et.lock.Unlock()
  59. if et.eventTraceKind == nil {
  60. // Return in the normal case
  61. return
  62. }
  63. whichKind := strings.Join(which.Kind(), ".")
  64. // Check if the event matches
  65. for i, tkind := range et.eventTraceKind {
  66. tstate := et.eventTraceState[i]
  67. regexMatch, _ := regexp.MatchString(tkind, whichKind)
  68. if whichKind == tkind || regexMatch {
  69. if tstate == nil || stateMatch(tstate, which.State()) {
  70. fmt.Fprintln(et.out, fmt.Sprintf("%v %v", tkind, where))
  71. for _, w := range what {
  72. fmt.Fprintln(et.out, fmt.Sprintf(" %v",
  73. stringutil.ConvertToString(w)))
  74. }
  75. fmt.Fprintln(et.out, fmt.Sprintf(" %v", which))
  76. }
  77. }
  78. }
  79. }
  80. // Helper functions
  81. // ================
  82. /*
  83. stateMatch checks if a given template matches a given event state.
  84. */
  85. func stateMatch(template, state map[interface{}]interface{}) bool {
  86. for k, v := range template {
  87. if sv, ok := state[k]; !ok {
  88. return false
  89. } else if v != nil {
  90. regexMatch, _ := regexp.MatchString(fmt.Sprint(v), fmt.Sprint(sv))
  91. if v != sv && !regexMatch {
  92. return false
  93. }
  94. }
  95. }
  96. return true
  97. }