rule.go 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805
  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. "bytes"
  13. "encoding/json"
  14. "fmt"
  15. "regexp"
  16. "sort"
  17. "strings"
  18. "sync"
  19. "devt.de/krotik/common/errorutil"
  20. "devt.de/krotik/common/sortutil"
  21. )
  22. /*
  23. Rule models a matching rule for event receivers (actions). A rule has 3 possible
  24. matching criteria:
  25. - Match on event kinds: A list of strings in dot notation which describes event kinds. May
  26. contain '*' characters as wildcards (e.g. core.tests.*).
  27. - Match on event cascade scope: A list of strings in dot notation which describe the
  28. required scopes of an event cascade.
  29. - Match on event state: A simple list of required key / value states in the event
  30. state. Nil values can be used as wildcards (i.e. match is only on key).
  31. Rules have priorities (0 being the highest) and may suppress each other.
  32. */
  33. type Rule struct {
  34. Name string // Name of the rule
  35. Desc string // Description of the rule (optional)
  36. KindMatch []string // Match on event kinds
  37. ScopeMatch []string // Match on event cascade scope
  38. StateMatch map[string]interface{} // Match on event state
  39. Priority int // Priority of the rule
  40. SuppressionList []string // List of suppressed rules by this rule
  41. Action RuleAction // Action of the rule
  42. }
  43. /*
  44. CopyAs returns a shallow copy of this rule with a new name.
  45. */
  46. func (r *Rule) CopyAs(newName string) *Rule {
  47. return &Rule{
  48. Name: newName,
  49. Desc: r.Desc,
  50. KindMatch: r.KindMatch,
  51. ScopeMatch: r.ScopeMatch,
  52. StateMatch: r.StateMatch,
  53. Priority: r.Priority,
  54. SuppressionList: r.SuppressionList,
  55. Action: r.Action,
  56. }
  57. }
  58. func (r *Rule) String() string {
  59. sm, _ := json.Marshal(r.StateMatch)
  60. return fmt.Sprintf("Rule:%s [%s] (Priority:%v Kind:%v Scope:%v StateMatch:%s Suppress:%v)",
  61. r.Name, strings.TrimSpace(r.Desc), r.Priority, r.KindMatch, r.ScopeMatch, sm, r.SuppressionList)
  62. }
  63. /*
  64. RuleAction is an action which is executed by a matching rule. The action gets
  65. a unique thread ID from the executing thread.
  66. */
  67. type RuleAction func(p Processor, m Monitor, e *Event, tid uint64) error
  68. /*
  69. RuleIndex is an index for rules. It takes the form of a tree structure in which
  70. incoming events are matched level by level (e.g. event of kind core.task1.step1
  71. is first matched by kind "core" then "task1" and then "step1". At the leaf of
  72. the index tree it may then be matched on a state condition).
  73. */
  74. type RuleIndex interface {
  75. /*
  76. AddRule adds a new rule to the index.
  77. */
  78. AddRule(rule *Rule) error
  79. /*
  80. IsTriggering checks if a given event triggers a rule in this index.
  81. */
  82. IsTriggering(event *Event) bool
  83. /*
  84. Match returns all rules in this index which match a given event. This
  85. method does a full matching check including state matching.
  86. */
  87. Match(event *Event) []*Rule
  88. /*
  89. String returns a string representation of this rule index and all subindexes.
  90. */
  91. String() string
  92. /*
  93. Rules returns all rules with the given prefix in the name. Use the empty
  94. string to return all rules.
  95. */
  96. Rules() map[string]*Rule
  97. }
  98. /*
  99. ruleSubIndex is a sub index used by a rule index.
  100. */
  101. type ruleSubIndex interface {
  102. /*
  103. type returns the type of the rule sub index.
  104. */
  105. Type() string
  106. /*
  107. addRuleAtLevel adds a new rule to the index at a specific level. The
  108. level is described by a part of the rule kind match.
  109. */
  110. addRuleAtLevel(rule *Rule, kindMatchLevel []string)
  111. /*
  112. isTriggeringAtLevel checks if a given event triggers a rule at the given
  113. level of the index.
  114. */
  115. isTriggeringAtLevel(event *Event, level int) bool
  116. /*
  117. matchAtLevel returns all rules in this index which match a given event
  118. at the given level. This method does a full matching check including
  119. state matching.
  120. */
  121. matchAtLevel(event *Event, level int) []*Rule
  122. /*
  123. stringIndent returns a string representation with a given indentation of this
  124. rule index and all subindexes.
  125. */
  126. stringIndent(indent string) string
  127. }
  128. /*
  129. ruleIndexRoot models the index root node.
  130. */
  131. type ruleIndexRoot struct {
  132. *RuleIndexKind
  133. rules map[string]*Rule
  134. }
  135. /*
  136. AddRule adds a new rule to the index.
  137. */
  138. func (r *ruleIndexRoot) AddRule(rule *Rule) error {
  139. if _, ok := r.rules[rule.Name]; ok {
  140. return fmt.Errorf("Cannot add rule %v twice", rule.Name)
  141. }
  142. r.rules[rule.Name] = rule
  143. return r.RuleIndexKind.AddRule(rule)
  144. }
  145. /*
  146. Rules returns all rules with the given prefix in the name. Use the empty
  147. string to return all rules.
  148. */
  149. func (r *ruleIndexRoot) Rules() map[string]*Rule {
  150. return r.rules
  151. }
  152. /*
  153. NewRuleIndex creates a new rule container for efficient event matching.
  154. */
  155. func NewRuleIndex() RuleIndex {
  156. return &ruleIndexRoot{newRuleIndexKind(), make(map[string]*Rule)}
  157. }
  158. /*
  159. Rule index types
  160. */
  161. const (
  162. typeRuleIndexKind = "RuleIndexKind"
  163. typeRuleIndexState = "RuleIndexState"
  164. typeRuleIndexAll = "RuleIndexAll"
  165. )
  166. // Rule Index Kind
  167. // ===============
  168. /*
  169. RuleIndexKind data structure.
  170. */
  171. type RuleIndexKind struct {
  172. id uint64 // Id of this rule index
  173. kindAllMatch []ruleSubIndex // Rules with target all events of a specific category
  174. kindSingleMatch map[string][]ruleSubIndex // Rules which target specific event kinds
  175. count int // Number of loaded rules
  176. }
  177. /*
  178. newRuleIndexKind creates a new rule index matching on event kind.
  179. */
  180. func newRuleIndexKind() *RuleIndexKind {
  181. return &RuleIndexKind{
  182. newRuleIndexID(),
  183. make([]ruleSubIndex, 0),
  184. make(map[string][]ruleSubIndex),
  185. 0,
  186. }
  187. }
  188. /*
  189. Type returns the type of the rule sub index.
  190. */
  191. func (ri *RuleIndexKind) Type() string {
  192. return typeRuleIndexKind
  193. }
  194. /*
  195. AddRule adds a new rule to the index.
  196. */
  197. func (ri *RuleIndexKind) AddRule(rule *Rule) error {
  198. // Check essential rule attributes
  199. if rule.KindMatch == nil || len(rule.KindMatch) == 0 {
  200. return fmt.Errorf("Cannot add rule without a kind match: %v", rule.Name)
  201. } else if rule.ScopeMatch == nil {
  202. return fmt.Errorf("Cannot add rule without a scope match: %v", rule.Name)
  203. }
  204. // Add rule to the index for all kind matches
  205. for _, kindMatch := range rule.KindMatch {
  206. ri.addRuleAtLevel(rule, strings.Split(kindMatch, RuleKindSeparator))
  207. ri.count++
  208. }
  209. return nil
  210. }
  211. /*
  212. addRuleAtLevel adds a new rule to the index at a specific level. The
  213. level is described by a part of the rule kind match.
  214. */
  215. func (ri *RuleIndexKind) addRuleAtLevel(rule *Rule, kindMatchLevel []string) {
  216. var indexType string
  217. var index ruleSubIndex
  218. var ruleSubIndexList []ruleSubIndex
  219. var ok bool
  220. // Pick the right index type
  221. if len(kindMatchLevel) == 1 {
  222. if rule.StateMatch != nil {
  223. indexType = typeRuleIndexState
  224. } else {
  225. indexType = typeRuleIndexAll
  226. }
  227. } else {
  228. indexType = typeRuleIndexKind
  229. }
  230. // Get (create when necessary) a sub index of a specific type for the
  231. // match item of this level
  232. matchItem := kindMatchLevel[0]
  233. // Select the correct ruleSubIndexList
  234. if matchItem == RuleKindWildcard {
  235. ruleSubIndexList = ri.kindAllMatch
  236. } else {
  237. if ruleSubIndexList, ok = ri.kindSingleMatch[matchItem]; !ok {
  238. ruleSubIndexList = make([]ruleSubIndex, 0)
  239. ri.kindSingleMatch[matchItem] = ruleSubIndexList
  240. }
  241. }
  242. // Check if the required index is already existing
  243. for _, item := range ruleSubIndexList {
  244. if item.Type() == indexType {
  245. index = item
  246. break
  247. }
  248. }
  249. // Create a new index if no index was found
  250. if index == nil {
  251. switch indexType {
  252. case typeRuleIndexState:
  253. index = newRuleIndexState()
  254. case typeRuleIndexAll:
  255. index = newRuleIndexAll()
  256. case typeRuleIndexKind:
  257. index = newRuleIndexKind()
  258. }
  259. // Add the new index to the correct list
  260. if matchItem == RuleKindWildcard {
  261. ri.kindAllMatch = append(ruleSubIndexList, index)
  262. } else {
  263. ri.kindSingleMatch[matchItem] = append(ruleSubIndexList, index)
  264. }
  265. }
  266. // Recurse into the next level
  267. index.addRuleAtLevel(rule, kindMatchLevel[1:])
  268. }
  269. /*
  270. IsTriggering checks if a given event triggers a rule in this index.
  271. */
  272. func (ri *RuleIndexKind) IsTriggering(event *Event) bool {
  273. return ri.isTriggeringAtLevel(event, 0)
  274. }
  275. /*
  276. isTriggeringAtLevel checks if a given event triggers a rule at the given
  277. level of the index.
  278. */
  279. func (ri *RuleIndexKind) isTriggeringAtLevel(event *Event, level int) bool {
  280. // Check if the event kind is too general (e.g. rule is defined as a.b.c
  281. // and the event kind is a.b)
  282. if len(event.kind) <= level {
  283. return false
  284. }
  285. levelKind := event.kind[level]
  286. nextLevel := level + 1
  287. // Check rules targeting all events
  288. for _, index := range ri.kindAllMatch {
  289. if index.isTriggeringAtLevel(event, nextLevel) {
  290. return true
  291. }
  292. }
  293. // Check rules targeting specific events
  294. if ruleSubIndexList, ok := ri.kindSingleMatch[levelKind]; ok {
  295. for _, index := range ruleSubIndexList {
  296. if index.isTriggeringAtLevel(event, nextLevel) {
  297. return true
  298. }
  299. }
  300. }
  301. return false
  302. }
  303. /*
  304. Match returns all rules in this index which match a given event. This method
  305. does a full matching check including state matching.
  306. */
  307. func (ri *RuleIndexKind) Match(event *Event) []*Rule {
  308. return ri.matchAtLevel(event, 0)
  309. }
  310. /*
  311. matchAtLevel returns all rules in this index which match a given event
  312. at the given level. This method does a full matching check including
  313. state matching.
  314. */
  315. func (ri *RuleIndexKind) matchAtLevel(event *Event, level int) []*Rule {
  316. // Check if the event kind is too general (e.g. rule is defined as a.b.c
  317. // and the event kind is a.b)
  318. if len(event.kind) <= level {
  319. return nil
  320. }
  321. var ret []*Rule
  322. levelKind := event.kind[level]
  323. nextLevel := level + 1
  324. // Check rules targeting all events
  325. for _, index := range ri.kindAllMatch {
  326. ret = append(ret, index.matchAtLevel(event, nextLevel)...)
  327. }
  328. // Check rules targeting specific events
  329. if ruleSubIndexList, ok := ri.kindSingleMatch[levelKind]; ok {
  330. for _, index := range ruleSubIndexList {
  331. ret = append(ret, index.matchAtLevel(event, nextLevel)...)
  332. }
  333. }
  334. return ret
  335. }
  336. /*
  337. String returns a string representation of this rule index and all subindexes.
  338. */
  339. func (ri *RuleIndexKind) String() string {
  340. return ri.stringIndent("")
  341. }
  342. /*
  343. stringIndent returns a string representation with a given indentation of this
  344. rule index and all subindexes.
  345. */
  346. func (ri *RuleIndexKind) stringIndent(indent string) string {
  347. var buf bytes.Buffer
  348. newIndent := indent + " "
  349. writeIndexList := func(name string, indexList []ruleSubIndex) {
  350. if len(indexList) > 0 {
  351. buf.WriteString(fmt.Sprint(indent, name))
  352. buf.WriteString(fmt.Sprintf(" - %v (%v)\n", ri.Type(), ri.id))
  353. for _, index := range indexList {
  354. buf.WriteString(index.stringIndent(newIndent))
  355. }
  356. }
  357. }
  358. writeIndexList("*", ri.kindAllMatch)
  359. var keys []string
  360. for k := range ri.kindSingleMatch {
  361. keys = append(keys, k)
  362. }
  363. sort.Strings(keys)
  364. for _, key := range keys {
  365. indexList := ri.kindSingleMatch[key]
  366. writeIndexList(key, indexList)
  367. }
  368. return buf.String()
  369. }
  370. // Rule Index State
  371. // ================
  372. /*
  373. RuleMatcherKey is used for pure key - value state matches.
  374. */
  375. type RuleMatcherKey struct {
  376. bits uint64
  377. bitsAny uint64
  378. bitsValue map[interface{}]uint64
  379. bitsRegexes map[uint64]*regexp.Regexp
  380. }
  381. /*
  382. addRule adds a new rule to this key matcher.
  383. */
  384. func (rm *RuleMatcherKey) addRule(num uint, bit uint64, key string, value interface{}) {
  385. // Register rule bit
  386. rm.bits |= bit
  387. if value == nil {
  388. rm.bitsAny |= bit
  389. } else if regex, ok := value.(*regexp.Regexp); ok {
  390. // For regex match we add a bit to the any mask so the presence of
  391. // the key is checked before the actual regex is checked
  392. rm.bitsAny |= bit
  393. rm.bitsRegexes[bit] = regex
  394. } else {
  395. rm.bitsValue[value] |= bit
  396. }
  397. }
  398. /*
  399. match adds matching rules to a given bit mask.
  400. */
  401. func (rm *RuleMatcherKey) match(bits uint64, value interface{}) uint64 {
  402. toRemove := rm.bitsAny ^ rm.bits
  403. if value != nil {
  404. if additionalBits, ok := rm.bitsValue[value]; ok {
  405. toRemove = rm.bitsAny | additionalBits ^ rm.bits
  406. }
  407. }
  408. keyMatchedBits := bits ^ (bits & toRemove)
  409. for bm, r := range rm.bitsRegexes {
  410. if keyMatchedBits&bm > 0 && !r.MatchString(fmt.Sprint(value)) {
  411. // Regex does not match remove the bit
  412. keyMatchedBits ^= keyMatchedBits & bm
  413. }
  414. }
  415. return keyMatchedBits
  416. }
  417. /*
  418. unmatch removes all registered rules in this
  419. */
  420. func (rm *RuleMatcherKey) unmatch(bits uint64) uint64 {
  421. return bits ^ (bits & rm.bits)
  422. }
  423. /*
  424. String returns a string representation of this key matcher.
  425. */
  426. func (rm *RuleMatcherKey) String() string {
  427. var buf bytes.Buffer
  428. buf.WriteString(fmt.Sprintf("%08X *:%08X", rm.bits, rm.bitsAny))
  429. buf.WriteString(" [")
  430. var keys []interface{}
  431. for k := range rm.bitsValue {
  432. keys = append(keys, k)
  433. }
  434. sortutil.InterfaceStrings(keys)
  435. for _, k := range keys {
  436. m := rm.bitsValue[k]
  437. buf.WriteString(fmt.Sprintf("%v:%08X ", k, m))
  438. }
  439. buf.WriteString("] [")
  440. var rkeys []uint64
  441. for k := range rm.bitsRegexes {
  442. rkeys = append(rkeys, k)
  443. }
  444. sortutil.UInt64s(rkeys)
  445. for _, k := range rkeys {
  446. r := rm.bitsRegexes[k]
  447. buf.WriteString(fmt.Sprintf("%08X:%v ", k, r))
  448. }
  449. buf.WriteString("]")
  450. return buf.String()
  451. }
  452. /*
  453. RuleIndexState data structure
  454. */
  455. type RuleIndexState struct {
  456. id uint64 // Id of this rule index
  457. rules []*Rule // All rules stored in this index
  458. keyMap map[string]*RuleMatcherKey // Map of keys (key or key and value) to KeyMatcher
  459. }
  460. /*
  461. newRuleIndexState creates a new rule index matching on event state.
  462. */
  463. func newRuleIndexState() *RuleIndexState {
  464. return &RuleIndexState{newRuleIndexID(), make([]*Rule, 0),
  465. make(map[string]*RuleMatcherKey)}
  466. }
  467. /*
  468. Type returns the type of the rule sub index.
  469. */
  470. func (ri *RuleIndexState) Type() string {
  471. return typeRuleIndexState
  472. }
  473. /*
  474. addRuleAtLevel adds a new rule to the index at a specific level. The
  475. level is described by a part of the rule kind match.
  476. */
  477. func (ri *RuleIndexState) addRuleAtLevel(rule *Rule, kindMatchLevel []string) {
  478. errorutil.AssertTrue(len(kindMatchLevel) == 0,
  479. fmt.Sprint("RuleIndexState must be a leaf - level is:", kindMatchLevel))
  480. num := uint(len(ri.rules))
  481. var bit uint64 = 1 << num
  482. ri.rules = append(ri.rules, rule)
  483. for k, v := range rule.StateMatch {
  484. var ok bool
  485. var keyMatcher *RuleMatcherKey
  486. if keyMatcher, ok = ri.keyMap[k]; !ok {
  487. keyMatcher = &RuleMatcherKey{0, 0, make(map[interface{}]uint64), make(map[uint64]*regexp.Regexp)}
  488. ri.keyMap[k] = keyMatcher
  489. }
  490. keyMatcher.addRule(num, bit, k, v)
  491. }
  492. }
  493. /*
  494. isTriggeringAtLevel checks if a given event triggers a rule at the given
  495. level of the index.
  496. */
  497. func (ri *RuleIndexState) isTriggeringAtLevel(event *Event, level int) bool {
  498. return len(event.kind) == level
  499. }
  500. /*
  501. matchAtLevel returns all rules in this index which match a given event
  502. at the given level. This method does a full matching check including
  503. state matching.
  504. */
  505. func (ri *RuleIndexState) matchAtLevel(event *Event, level int) []*Rule {
  506. if len(event.kind) != level {
  507. return nil
  508. }
  509. // Assume all rules match and remove the ones with don't
  510. var matchBits uint64 = (1 << uint(len(ri.rules))) - 1
  511. // Match key and values
  512. for key, matcher := range ri.keyMap {
  513. if val, ok := event.state[key]; ok {
  514. // Key is present in event
  515. matchBits = matcher.match(matchBits, val)
  516. } else {
  517. // Key is not present in event - remove all rules which require the key
  518. matchBits = matcher.unmatch(matchBits)
  519. }
  520. if matchBits == 0 {
  521. // All rules have been excluded
  522. return nil
  523. }
  524. }
  525. var ret []*Rule
  526. var collectionBits uint64 = 1
  527. // Collect matched rules
  528. for i := 0; collectionBits <= matchBits; i++ {
  529. if matchBits&collectionBits > 0 {
  530. ret = append(ret, ri.rules[i])
  531. }
  532. collectionBits <<= 1
  533. }
  534. return ret
  535. }
  536. /*
  537. stringIndent returns a string representation with a given indentation of this
  538. rule index and all subindexes.
  539. */
  540. func (ri *RuleIndexState) stringIndent(indent string) string {
  541. var buf bytes.Buffer
  542. buf.WriteString(fmt.Sprintf("%v%v (%v) ", indent, ri.Type(), ri.id))
  543. buf.WriteString("[")
  544. for _, r := range ri.rules {
  545. buf.WriteString(fmt.Sprintf("%v ", r.Name))
  546. }
  547. buf.WriteString("]\n")
  548. newIndent := indent + " "
  549. var keys []string
  550. for k := range ri.keyMap {
  551. keys = append(keys, k)
  552. }
  553. sort.Strings(keys)
  554. for _, k := range keys {
  555. m := ri.keyMap[k]
  556. buf.WriteString(fmt.Sprintf("%v%v - %v\n", newIndent, k, m))
  557. }
  558. return buf.String()
  559. }
  560. // Rule Index All
  561. // ==============
  562. /*
  563. RuleIndexAll data structure.
  564. */
  565. type RuleIndexAll struct {
  566. id uint64 // Id of this rule index
  567. rules []*Rule // Rules with target all events of a specific category
  568. }
  569. /*
  570. newRuleIndexAll creates a new leaf rule index matching on all events.
  571. */
  572. func newRuleIndexAll() *RuleIndexAll {
  573. return &RuleIndexAll{newRuleIndexID(), make([]*Rule, 0)}
  574. }
  575. /*
  576. Type returns the type of the rule sub index.
  577. */
  578. func (ri *RuleIndexAll) Type() string {
  579. return typeRuleIndexAll
  580. }
  581. /*
  582. addRuleAtLevel adds a new rule to the index at a specific level. The
  583. level is described by a part of the rule kind match.
  584. */
  585. func (ri *RuleIndexAll) addRuleAtLevel(rule *Rule, kindMatchLevel []string) {
  586. ri.rules = append(ri.rules, rule)
  587. }
  588. /*
  589. isTriggeringAtLevel checks if a given event triggers a rule at the given
  590. level of the index.
  591. */
  592. func (ri *RuleIndexAll) isTriggeringAtLevel(event *Event, level int) bool {
  593. return len(event.kind) == level
  594. }
  595. /*
  596. matchAtLevel returns all rules in this index which match a given event
  597. at the given level. This method does a full matching check including
  598. state matching.
  599. */
  600. func (ri *RuleIndexAll) matchAtLevel(event *Event, level int) []*Rule {
  601. if len(event.kind) != level {
  602. return nil
  603. }
  604. return ri.rules
  605. }
  606. /*
  607. stringIndent returns a string representation with a given indentation of this
  608. rule index and all subindexes.
  609. */
  610. func (ri *RuleIndexAll) stringIndent(indent string) string {
  611. var buf bytes.Buffer
  612. buf.WriteString(fmt.Sprintf("%v%v (%v)\n", indent, ri.Type(), ri.id))
  613. newIndent := indent + " "
  614. for _, rule := range ri.rules {
  615. buf.WriteString(fmt.Sprintf("%v%v\n", newIndent, rule))
  616. }
  617. return buf.String()
  618. }
  619. // Unique id creation
  620. // ==================
  621. var ruleindexidcounter uint64 = 1
  622. var ruleindexidcounterLock = &sync.Mutex{}
  623. /*
  624. newId returns a new unique id.
  625. */
  626. func newRuleIndexID() uint64 {
  627. ruleindexidcounterLock.Lock()
  628. defer ruleindexidcounterLock.Unlock()
  629. ret := ruleindexidcounter
  630. ruleindexidcounter++
  631. return ret
  632. }