statsd_exporter/pkg/mapper/fsm
Mark Sagi-Kazar 278a862099
refactor: use go-kit logger instead of deprecated common log package
Signed-off-by: Mark Sagi-Kazar <mark.sagikazar@gmail.com>
2021-06-07 16:00:08 +02:00
..
dump.go optimizations 2018-10-03 16:31:00 -07:00
formatter.go Copy edit comments in fsm/formatter 2018-10-10 21:31:51 +00:00
fsm.go refactor: use go-kit logger instead of deprecated common log package 2021-06-07 16:00:08 +02:00
fsm.png Copy edits in FSM README 2018-10-10 21:22:53 +00:00
minmax.go license header 2018-09-21 18:13:23 -07:00
README.md Rename timer to observer in mapper 2020-06-15 17:26:20 -04:00

FSM Mapping

Overview

This package implements a fast and efficient algorithm for generic glob style string matching using a finite state machine (FSM).

Source Hierachy

  '-- fsm
      '-- dump.go // functionality to dump the FSM to Dot file
      '-- formatter.go // format glob templates using captured * groups
      '-- fsm.go // manipulating and searching of FSM
      '-- minmax.go // min() max() function for interger

FSM Explained

Per Wikipedia:

A finite-state machine (FSM) or finite-state automaton (FSA, plural: automata), finite automaton, or simply a state machine, is a mathematical model of computation. It is an abstract machine that can be in exactly one of a finite number of states at any given time. The FSM can change from one state to another in response to some external inputs; the change from one state to another is called a transition. An FSM is defined by a list of its states, its initial state, and the conditions for each transition.

In our use case, each state is a substring after the input StatsD metric name is splitted by ..

Add state to FSM

func (f *FSM) AddState(match string, matchMetricType string, maxPossibleTransitions int, result interface{}) int

At first, the FSM only contains three states, representing three possible metric types:

       ____ [gauge]
      /
(start)---- [counter]
      \
       '--- [observer]

Adding a rule client.*.request.count with type counter will make the FSM to be:

       ____ [gauge]
      /
(start)---- [counter] -- [client] -- [*] -- [request] -- [count] -- {R1}
      \
       '--- [observer]

{R1} is short for result 1, which is the match result for client.*.request.count.

Adding a rule client.*.*.size with type counter will make the FSM to be:

       ____ [gauge]                      __ [request] -- [count] -- {R1}
      /                                 /
(start)---- [counter] -- [client] -- [*]
      \                                  \__ [*] -- [size] -- {R2}
       '--- [observer]

Finding a result state in FSM

func (f *FSM) GetMapping(statsdMetric string, statsdMetricType string) (*mappingState, []string)

For example, when mapping client.aaa.request.count with counter type in the FSM, the ^1 to ^7 symbols indicate how FSM will traversal in its tree:

       ____ [gauge]                      __ [request] -- [count] -- {R1}
      /                                 /       ^5        ^6         ^7
(start)---- [counter] -- [client] -- [*]
   ^1 \          ^2           ^3        \__ [*] -- [size] -- {R2}
       '--- [observer]                ^4 

To map client.bbb.request.size, FSM will do a backtracking:

       ____ [gauge]                      __ [request] -- [count] -- {R1}
      /                                 /       ^5         ^6
(start)---- [counter] -- [client] -- [*]
   ^1 \          ^2           ^3        \__ [*] -- [size] -- {R2}
       '--- [observer]                ^4
                                             ^7      ^8        ^9

Debugging

To see all the states of the current FSM, use func (f *FSM) DumpFSM(w io.Writer) to dump into a Dot file. The Dot file can be further renderer into image using:

$ dot -Tpng dump.dot > dump.png

In StatsD exporter, one could use the following:

$ statsd_exporter --statsd.mapping-config=statsd.rules --debug.dump-fsm=dump.dot
$ dot -Tpng dump.dot > dump.png

For example, the following rules:

mappings:
- match: client.*.request.count
  name: request_count
  match_metric_type: counter
  labels:
    client: $1

- match: client.*.*.size
  name: sizes
  match_metric_type: counter
  labels:
    client: $1
    direction: $2

will be rendered as:

FSM

The dot program is part of Graphviz and is available in most of popular operating systems.