vector.yml 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268
  1. api:
  2. enabled: true
  3. address: 0.0.0.0:9001
  4. sources:
  5. docker_host:
  6. type: docker_logs
  7. exclude_containers:
  8. - briven-vector
  9. transforms:
  10. project_logs:
  11. type: remap
  12. inputs:
  13. - docker_host
  14. source: |-
  15. .project = "default"
  16. .event_message = del(.message)
  17. .appname = del(.container_name)
  18. del(.container_created_at)
  19. del(.container_id)
  20. del(.source_type)
  21. del(.stream)
  22. del(.label)
  23. del(.image)
  24. del(.host)
  25. del(.stream)
  26. router:
  27. type: route
  28. inputs:
  29. - project_logs
  30. route:
  31. kong: '.appname == "briven-kong" || .appname == "briven-envoy"'
  32. auth: '.appname == "briven-auth"'
  33. rest: '.appname == "briven-rest"'
  34. realtime: '.appname == "realtime-dev.briven-realtime"'
  35. storage: '.appname == "briven-storage"'
  36. functions: '.appname == "briven-edge-functions"'
  37. db: '.appname == "briven-db"'
  38. # Ignores non nginx errors since they are related with kong booting up
  39. kong_logs:
  40. type: remap
  41. inputs:
  42. - router.kong
  43. source: |-
  44. req, err = parse_nginx_log(.event_message, "combined")
  45. if err == null {
  46. .timestamp = req.timestamp
  47. .metadata.request.headers.referer = req.referer
  48. .metadata.request.headers.user_agent = req.agent
  49. .metadata.request.headers.cf_connecting_ip = req.client
  50. .metadata.response.status_code = req.status
  51. url, split_err = split(req.request, " ")
  52. if split_err == null {
  53. .metadata.request.method = url[0]
  54. .metadata.request.path = url[1]
  55. .metadata.request.protocol = url[2]
  56. }
  57. }
  58. if err != null {
  59. abort
  60. }
  61. # Ignores non nginx errors since they are related with kong booting up
  62. kong_err:
  63. type: remap
  64. inputs:
  65. - router.kong
  66. source: |-
  67. .metadata.request.method = "GET"
  68. .metadata.response.status_code = 200
  69. parsed, err = parse_nginx_log(.event_message, "error")
  70. if err == null {
  71. .timestamp = parsed.timestamp
  72. .severity = parsed.severity
  73. .metadata.request.host = parsed.host
  74. .metadata.request.headers.cf_connecting_ip = parsed.client
  75. url, err = split(parsed.request, " ")
  76. if err == null {
  77. .metadata.request.method = url[0]
  78. .metadata.request.path = url[1]
  79. .metadata.request.protocol = url[2]
  80. }
  81. }
  82. if err != null {
  83. abort
  84. }
  85. # Gotrue logs are structured json strings which frontend parses directly. But we keep metadata for consistency.
  86. auth_logs:
  87. type: remap
  88. inputs:
  89. - router.auth
  90. source: |-
  91. parsed, err = parse_json(.event_message)
  92. if err == null {
  93. .metadata.timestamp = parsed.time
  94. .metadata = merge!(.metadata, parsed)
  95. }
  96. # PostgREST logs are structured so we separate timestamp from message using regex
  97. rest_logs:
  98. type: remap
  99. inputs:
  100. - router.rest
  101. source: |-
  102. parsed, err = parse_regex(.event_message, r'^(?P<time>.*): (?P<msg>.*)$')
  103. if err == null {
  104. .event_message = parsed.msg
  105. .timestamp = parse_timestamp!(value: parsed.time,format: "%d/%b/%Y:%H:%M:%S %z")
  106. .metadata.host = .project
  107. }
  108. # Filter out healthcheck logs from Realtime
  109. realtime_logs_filtered:
  110. type: filter
  111. inputs:
  112. - router.realtime
  113. condition: '!contains(string!(.event_message), "/health")'
  114. # Realtime logs are structured so we parse the severity level using regex (ignore time because it has no date)
  115. realtime_logs:
  116. type: remap
  117. inputs:
  118. - realtime_logs_filtered
  119. source: |-
  120. .metadata.project = del(.project)
  121. .metadata.external_id = .metadata.project
  122. parsed, err = parse_regex(.event_message, r'^(?P<time>\d+:\d+:\d+\.\d+) \[(?P<level>\w+)\] (?P<msg>.*)$')
  123. if err == null {
  124. .event_message = parsed.msg
  125. .metadata.level = parsed.level
  126. }
  127. # Function logs are unstructured messages on stderr
  128. functions_logs:
  129. type: remap
  130. inputs:
  131. - router.functions
  132. source: |-
  133. .metadata.project_ref = del(.project)
  134. # Storage logs may contain json objects so we parse them for completeness
  135. storage_logs:
  136. type: remap
  137. inputs:
  138. - router.storage
  139. source: |-
  140. .metadata.project = del(.project)
  141. .metadata.tenantId = .metadata.project
  142. parsed, err = parse_json(.event_message)
  143. if err == null {
  144. .event_message = parsed.msg
  145. .metadata.level = parsed.level
  146. .metadata.timestamp = parsed.time
  147. .metadata.context[0].host = parsed.hostname
  148. .metadata.context[0].pid = parsed.pid
  149. }
  150. # Postgres logs some messages to stderr which we map to warning severity level
  151. db_logs:
  152. type: remap
  153. inputs:
  154. - router.db
  155. source: |-
  156. .metadata.host = "db-default"
  157. .metadata.parsed.timestamp = .timestamp
  158. parsed, err = parse_regex(.event_message, r'.*(?P<level>INFO|NOTICE|WARNING|ERROR|LOG|FATAL|PANIC?):.*', numeric_groups: true)
  159. if err != null || parsed == null {
  160. .metadata.parsed.error_severity = "info"
  161. }
  162. if parsed.level != null {
  163. .metadata.parsed.error_severity = parsed.level
  164. }
  165. if .metadata.parsed.error_severity == "info" {
  166. .metadata.parsed.error_severity = "log"
  167. }
  168. .metadata.parsed.error_severity = upcase!(.metadata.parsed.error_severity)
  169. sinks:
  170. logflare_auth:
  171. type: 'http'
  172. inputs:
  173. - auth_logs
  174. encoding:
  175. codec: 'json'
  176. method: 'post'
  177. request:
  178. retry_max_duration_secs: 30
  179. retry_initial_backoff_secs: 1
  180. headers:
  181. x-api-key: ${LOGFLARE_PUBLIC_ACCESS_TOKEN?LOGFLARE_PUBLIC_ACCESS_TOKEN is required}
  182. uri: 'http://analytics:4000/api/logs?source_name=gotrue.logs.prod'
  183. logflare_realtime:
  184. type: 'http'
  185. inputs:
  186. - realtime_logs
  187. encoding:
  188. codec: 'json'
  189. method: 'post'
  190. request:
  191. retry_max_duration_secs: 30
  192. retry_initial_backoff_secs: 1
  193. headers:
  194. x-api-key: ${LOGFLARE_PUBLIC_ACCESS_TOKEN?LOGFLARE_PUBLIC_ACCESS_TOKEN is required}
  195. uri: 'http://analytics:4000/api/logs?source_name=realtime.logs.prod'
  196. logflare_rest:
  197. type: 'http'
  198. inputs:
  199. - rest_logs
  200. encoding:
  201. codec: 'json'
  202. method: 'post'
  203. request:
  204. retry_max_duration_secs: 30
  205. retry_initial_backoff_secs: 1
  206. headers:
  207. x-api-key: ${LOGFLARE_PUBLIC_ACCESS_TOKEN?LOGFLARE_PUBLIC_ACCESS_TOKEN is required}
  208. uri: 'http://analytics:4000/api/logs?source_name=postgREST.logs.prod'
  209. logflare_db:
  210. type: 'http'
  211. inputs:
  212. - db_logs
  213. encoding:
  214. codec: 'json'
  215. method: 'post'
  216. request:
  217. retry_max_duration_secs: 30
  218. retry_initial_backoff_secs: 1
  219. headers:
  220. x-api-key: ${LOGFLARE_PUBLIC_ACCESS_TOKEN?LOGFLARE_PUBLIC_ACCESS_TOKEN is required}
  221. # Route directly to analytics like other sinks. Retry handles the startup
  222. # race where analytics may not be ready yet when early DB logs arrive.
  223. uri: 'http://analytics:4000/api/logs?source_name=postgres.logs'
  224. logflare_functions:
  225. type: 'http'
  226. inputs:
  227. - functions_logs
  228. encoding:
  229. codec: 'json'
  230. method: 'post'
  231. request:
  232. retry_max_duration_secs: 30
  233. retry_initial_backoff_secs: 1
  234. headers:
  235. x-api-key: ${LOGFLARE_PUBLIC_ACCESS_TOKEN?LOGFLARE_PUBLIC_ACCESS_TOKEN is required}
  236. uri: 'http://analytics:4000/api/logs?source_name=deno-relay-logs'
  237. logflare_storage:
  238. type: 'http'
  239. inputs:
  240. - storage_logs
  241. encoding:
  242. codec: 'json'
  243. method: 'post'
  244. request:
  245. retry_max_duration_secs: 30
  246. retry_initial_backoff_secs: 1
  247. headers:
  248. x-api-key: ${LOGFLARE_PUBLIC_ACCESS_TOKEN?LOGFLARE_PUBLIC_ACCESS_TOKEN is required}
  249. uri: 'http://analytics:4000/api/logs?source_name=storage.logs.prod.2'
  250. logflare_kong:
  251. type: 'http'
  252. inputs:
  253. - kong_logs
  254. - kong_err
  255. encoding:
  256. codec: 'json'
  257. method: 'post'
  258. request:
  259. retry_max_duration_secs: 30
  260. retry_initial_backoff_secs: 1
  261. headers:
  262. x-api-key: ${LOGFLARE_PUBLIC_ACCESS_TOKEN?LOGFLARE_PUBLIC_ACCESS_TOKEN is required}
  263. uri: 'http://analytics:4000/api/logs?source_name=cloudflare.logs.prod'