PageRenderTime 54ms CodeModel.GetById 27ms RepoModel.GetById 0ms app.codeStats 0ms

/message/message_matcher.go

https://gitlab.com/wilane/heka
Go | 245 lines | 210 code | 16 blank | 19 comment | 81 complexity | c37951b1428d4a44356a037168d0d729 MD5 | raw file
  1. /***** BEGIN LICENSE BLOCK *****
  2. # This Source Code Form is subject to the terms of the Mozilla Public
  3. # License, v. 2.0. If a copy of the MPL was not distributed with this file,
  4. # You can obtain one at http://mozilla.org/MPL/2.0/.
  5. #
  6. # The Initial Developer of the Original Code is the Mozilla Foundation.
  7. # Portions created by the Initial Developer are Copyright (C) 2012
  8. # the Initial Developer. All Rights Reserved.
  9. #
  10. # Contributor(s):
  11. # Mike Trinkala (trink@mozilla.com)
  12. #
  13. # ***** END LICENSE BLOCK *****/
  14. package message
  15. import "strings"
  16. // MatcherSpecification used by the message router to distribute messages
  17. type MatcherSpecification struct {
  18. vm *tree
  19. spec string
  20. }
  21. // CreateMatcherSpecification compiles the spec string into a simple
  22. // virtual machine for execution
  23. func CreateMatcherSpecification(spec string) (*MatcherSpecification, error) {
  24. ms := new(MatcherSpecification)
  25. ms.spec = spec
  26. err := parseMatcherSpecification(ms)
  27. if err != nil {
  28. return nil, err
  29. }
  30. return ms, nil
  31. }
  32. // Match compares the message against the matcher spec and return the match
  33. // result
  34. func (m *MatcherSpecification) Match(message *Message) bool {
  35. return evalMatcherSpecification(m.vm, message)
  36. }
  37. // String outputs the spec as text
  38. func (m *MatcherSpecification) String() string {
  39. return m.spec
  40. }
  41. func evalMatcherSpecification(t *tree, msg *Message) (b bool) {
  42. if t == nil {
  43. return false
  44. }
  45. if t.left != nil {
  46. b = evalMatcherSpecification(t.left, msg)
  47. } else {
  48. return testExpr(msg, t.stmt)
  49. }
  50. if b == true && t.stmt.op.tokenId == OP_OR {
  51. return // short circuit
  52. }
  53. if b == false && t.stmt.op.tokenId == OP_AND {
  54. return // short circuit
  55. }
  56. if t.right != nil {
  57. b = evalMatcherSpecification(t.right, msg)
  58. }
  59. return
  60. }
  61. func getStringValue(msg *Message, stmt *Statement) string {
  62. switch stmt.field.tokenId {
  63. case VAR_UUID:
  64. return msg.GetUuidString()
  65. case VAR_TYPE:
  66. return msg.GetType()
  67. case VAR_LOGGER:
  68. return msg.GetLogger()
  69. case VAR_PAYLOAD:
  70. return msg.GetPayload()
  71. case VAR_ENVVERSION:
  72. return msg.GetEnvVersion()
  73. case VAR_HOSTNAME:
  74. return msg.GetHostname()
  75. }
  76. return ""
  77. }
  78. func getNumericValue(msg *Message, stmt *Statement) float64 {
  79. switch stmt.field.tokenId {
  80. case VAR_TIMESTAMP:
  81. return float64(msg.GetTimestamp())
  82. case VAR_SEVERITY:
  83. return float64(msg.GetSeverity())
  84. case VAR_PID:
  85. return float64(msg.GetPid())
  86. }
  87. return 0
  88. }
  89. func stringTest(s string, stmt *Statement) bool {
  90. if stmt.value.tokenId == NUMERIC_VALUE {
  91. return false
  92. }
  93. switch stmt.op.tokenId {
  94. case OP_EQ:
  95. if stmt.value.tokenId == NIL_VALUE {
  96. return false
  97. }
  98. return (s == stmt.value.token)
  99. case OP_NE:
  100. if stmt.value.tokenId == NIL_VALUE {
  101. return true
  102. }
  103. return (s != stmt.value.token)
  104. case OP_LT:
  105. return (s < stmt.value.token)
  106. case OP_LTE:
  107. return (s <= stmt.value.token)
  108. case OP_GT:
  109. return (s > stmt.value.token)
  110. case OP_GTE:
  111. return (s >= stmt.value.token)
  112. case OP_RE:
  113. if stmt.value.regexp != nil {
  114. return stmt.value.regexp.MatchString(s)
  115. } else if stmt.value.fieldIndex == STARTS_WITH {
  116. return strings.HasPrefix(s, stmt.value.token)
  117. } else if stmt.value.fieldIndex == ENDS_WITH {
  118. return strings.HasSuffix(s, stmt.value.token)
  119. }
  120. case OP_NRE:
  121. if stmt.value.regexp != nil {
  122. return !stmt.value.regexp.MatchString(s)
  123. } else if stmt.value.fieldIndex == STARTS_WITH {
  124. return !strings.HasPrefix(s, stmt.value.token)
  125. } else if stmt.value.fieldIndex == ENDS_WITH {
  126. return !strings.HasSuffix(s, stmt.value.token)
  127. }
  128. }
  129. return false
  130. }
  131. func numericTest(f float64, stmt *Statement) bool {
  132. if !(stmt.value.tokenId == NUMERIC_VALUE || stmt.value.tokenId == NIL_VALUE) {
  133. return false
  134. }
  135. switch stmt.op.tokenId {
  136. case OP_EQ:
  137. if stmt.value.tokenId == NIL_VALUE {
  138. return false
  139. }
  140. return (f == stmt.value.double)
  141. case OP_NE:
  142. if stmt.value.tokenId == NIL_VALUE {
  143. return true
  144. }
  145. return (f != stmt.value.double)
  146. case OP_LT:
  147. return (f < stmt.value.double)
  148. case OP_LTE:
  149. return (f <= stmt.value.double)
  150. case OP_GT:
  151. return (f > stmt.value.double)
  152. case OP_GTE:
  153. return (f >= stmt.value.double)
  154. }
  155. return false
  156. }
  157. func testNonExistence(stmt *Statement) bool {
  158. return (stmt.value.tokenId == NIL_VALUE && stmt.op.tokenId == OP_EQ)
  159. }
  160. func testExpr(msg *Message, stmt *Statement) bool {
  161. switch stmt.op.tokenId {
  162. case TRUE:
  163. return true
  164. case FALSE:
  165. return false
  166. default:
  167. switch stmt.field.tokenId {
  168. case VAR_UUID, VAR_TYPE, VAR_LOGGER, VAR_PAYLOAD,
  169. VAR_ENVVERSION, VAR_HOSTNAME:
  170. return stringTest(getStringValue(msg, stmt), stmt)
  171. case VAR_TIMESTAMP, VAR_SEVERITY, VAR_PID:
  172. return numericTest(getNumericValue(msg, stmt), stmt)
  173. case VAR_FIELDS:
  174. fi := stmt.field.fieldIndex
  175. ai := stmt.field.arrayIndex
  176. var field *Field
  177. if fi != 0 {
  178. fields := msg.FindAllFields(stmt.field.token)
  179. if fi >= len(fields) {
  180. return testNonExistence(stmt)
  181. }
  182. field = fields[fi]
  183. } else {
  184. if field = msg.FindFirstField(stmt.field.token); field == nil {
  185. return testNonExistence(stmt)
  186. }
  187. }
  188. switch field.GetValueType() {
  189. case Field_STRING:
  190. if ai >= len(field.ValueString) {
  191. return testNonExistence(stmt)
  192. }
  193. return stringTest(field.ValueString[ai], stmt)
  194. case Field_BYTES:
  195. if ai >= len(field.ValueBytes) {
  196. return testNonExistence(stmt)
  197. }
  198. return stringTest(string(field.ValueBytes[ai]), stmt)
  199. case Field_INTEGER:
  200. if ai >= len(field.ValueInteger) {
  201. return testNonExistence(stmt)
  202. }
  203. return numericTest(float64(field.ValueInteger[ai]), stmt)
  204. case Field_DOUBLE:
  205. if ai >= len(field.ValueDouble) {
  206. return testNonExistence(stmt)
  207. }
  208. return numericTest(field.ValueDouble[ai], stmt)
  209. case Field_BOOL:
  210. if ai >= len(field.ValueBool) {
  211. return testNonExistence(stmt)
  212. }
  213. if stmt.value.tokenId == NIL_VALUE {
  214. if stmt.op.tokenId == OP_EQ {
  215. return false
  216. }
  217. return true
  218. }
  219. b := field.ValueBool[ai]
  220. if stmt.value.tokenId == TRUE {
  221. return (b == true)
  222. } else {
  223. return (b == false)
  224. }
  225. }
  226. }
  227. }
  228. return false
  229. }