github.com/yankunsam/loki/v2@v2.6.3-0.20220817130409-389df5235c27/pkg/logql/log/fmt.go (about)

     1  package log
     2  
     3  import (
     4  	"bytes"
     5  	"fmt"
     6  	"strings"
     7  	"text/template"
     8  	"text/template/parse"
     9  	"time"
    10  
    11  	"github.com/Masterminds/sprig/v3"
    12  	"github.com/grafana/regexp"
    13  
    14  	"github.com/grafana/loki/pkg/logqlmodel"
    15  )
    16  
    17  const (
    18  	functionLineName      = "__line__"
    19  	functionTimestampName = "__timestamp__"
    20  )
    21  
    22  var (
    23  	_ Stage = &LineFormatter{}
    24  	_ Stage = &LabelsFormatter{}
    25  
    26  	// Available map of functions for the text template engine.
    27  	functionMap = template.FuncMap{
    28  		// olds functions deprecated.
    29  		"ToLower":    strings.ToLower,
    30  		"ToUpper":    strings.ToUpper,
    31  		"Replace":    strings.Replace,
    32  		"Trim":       strings.Trim,
    33  		"TrimLeft":   strings.TrimLeft,
    34  		"TrimRight":  strings.TrimRight,
    35  		"TrimPrefix": strings.TrimPrefix,
    36  		"TrimSuffix": strings.TrimSuffix,
    37  		"TrimSpace":  strings.TrimSpace,
    38  		"regexReplaceAll": func(regex string, s string, repl string) string {
    39  			r := regexp.MustCompile(regex)
    40  			return r.ReplaceAllString(s, repl)
    41  		},
    42  		"regexReplaceAllLiteral": func(regex string, s string, repl string) string {
    43  			r := regexp.MustCompile(regex)
    44  			return r.ReplaceAllLiteralString(s, repl)
    45  		},
    46  	}
    47  
    48  	// sprig template functions
    49  	templateFunctions = []string{
    50  		"lower",
    51  		"upper",
    52  		"title",
    53  		"trunc",
    54  		"substr",
    55  		"contains",
    56  		"hasPrefix",
    57  		"hasSuffix",
    58  		"indent",
    59  		"nindent",
    60  		"replace",
    61  		"repeat",
    62  		"trim",
    63  		"trimAll",
    64  		"trimSuffix",
    65  		"trimPrefix",
    66  		"int",
    67  		"float64",
    68  		"add",
    69  		"sub",
    70  		"mul",
    71  		"div",
    72  		"mod",
    73  		"addf",
    74  		"subf",
    75  		"mulf",
    76  		"divf",
    77  		"max",
    78  		"min",
    79  		"maxf",
    80  		"minf",
    81  		"ceil",
    82  		"floor",
    83  		"round",
    84  		"fromJson",
    85  		"date",
    86  		"toDate",
    87  		"now",
    88  		"unixEpoch",
    89  		"default",
    90  	}
    91  )
    92  
    93  func init() {
    94  	sprigFuncMap := sprig.GenericFuncMap()
    95  	for _, v := range templateFunctions {
    96  		if function, ok := sprigFuncMap[v]; ok {
    97  			functionMap[v] = function
    98  		}
    99  	}
   100  }
   101  
   102  type LineFormatter struct {
   103  	*template.Template
   104  	buf *bytes.Buffer
   105  
   106  	currentLine []byte
   107  	currentTs   int64
   108  }
   109  
   110  // NewFormatter creates a new log line formatter from a given text template.
   111  func NewFormatter(tmpl string) (*LineFormatter, error) {
   112  	lf := &LineFormatter{
   113  		buf: bytes.NewBuffer(make([]byte, 4096)),
   114  	}
   115  	functions := make(map[string]interface{}, len(functionMap)+1)
   116  	for k, v := range functionMap {
   117  		functions[k] = v
   118  	}
   119  	functions[functionLineName] = func() string {
   120  		return unsafeGetString(lf.currentLine)
   121  	}
   122  	functions[functionTimestampName] = func() time.Time {
   123  		return time.Unix(0, lf.currentTs)
   124  	}
   125  	t, err := template.New("line").Option("missingkey=zero").Funcs(functions).Parse(tmpl)
   126  	if err != nil {
   127  		return nil, fmt.Errorf("invalid line template: %w", err)
   128  	}
   129  	lf.Template = t
   130  	return lf, nil
   131  }
   132  
   133  func (lf *LineFormatter) Process(ts int64, line []byte, lbs *LabelsBuilder) ([]byte, bool) {
   134  	lf.buf.Reset()
   135  	lf.currentLine = line
   136  	lf.currentTs = ts
   137  
   138  	if err := lf.Template.Execute(lf.buf, lbs.Map()); err != nil {
   139  		lbs.SetErr(errTemplateFormat)
   140  		lbs.SetErrorDetails(err.Error())
   141  		return line, true
   142  	}
   143  	return lf.buf.Bytes(), true
   144  }
   145  
   146  func (lf *LineFormatter) RequiredLabelNames() []string {
   147  	return uniqueString(listNodeFields([]parse.Node{lf.Root}))
   148  }
   149  
   150  func listNodeFields(nodes []parse.Node) []string {
   151  	var res []string
   152  	for _, node := range nodes {
   153  		switch node.Type() {
   154  		case parse.NodePipe:
   155  			res = append(res, listNodeFieldsFromPipe(node.(*parse.PipeNode))...)
   156  		case parse.NodeAction:
   157  			res = append(res, listNodeFieldsFromPipe(node.(*parse.ActionNode).Pipe)...)
   158  		case parse.NodeList:
   159  			res = append(res, listNodeFields(node.(*parse.ListNode).Nodes)...)
   160  		case parse.NodeCommand:
   161  			res = append(res, listNodeFields(node.(*parse.CommandNode).Args)...)
   162  		case parse.NodeIf, parse.NodeWith, parse.NodeRange:
   163  			res = append(res, listNodeFieldsFromBranch(node)...)
   164  		case parse.NodeField:
   165  			res = append(res, node.(*parse.FieldNode).Ident...)
   166  		}
   167  	}
   168  	return res
   169  }
   170  
   171  func listNodeFieldsFromBranch(node parse.Node) []string {
   172  	var res []string
   173  	var b parse.BranchNode
   174  	switch node.Type() {
   175  	case parse.NodeIf:
   176  		b = node.(*parse.IfNode).BranchNode
   177  	case parse.NodeWith:
   178  		b = node.(*parse.WithNode).BranchNode
   179  	case parse.NodeRange:
   180  		b = node.(*parse.RangeNode).BranchNode
   181  	default:
   182  		return res
   183  	}
   184  	if b.Pipe != nil {
   185  		res = append(res, listNodeFieldsFromPipe(b.Pipe)...)
   186  	}
   187  	if b.List != nil {
   188  		res = append(res, listNodeFields(b.List.Nodes)...)
   189  	}
   190  	if b.ElseList != nil {
   191  		res = append(res, listNodeFields(b.ElseList.Nodes)...)
   192  	}
   193  	return res
   194  }
   195  
   196  func listNodeFieldsFromPipe(p *parse.PipeNode) []string {
   197  	var res []string
   198  	for _, c := range p.Cmds {
   199  		res = append(res, listNodeFields(c.Args)...)
   200  	}
   201  	return res
   202  }
   203  
   204  // LabelFmt is a configuration struct for formatting a label.
   205  type LabelFmt struct {
   206  	Name  string
   207  	Value string
   208  
   209  	Rename bool
   210  }
   211  
   212  // NewRenameLabelFmt creates a configuration to rename a label.
   213  func NewRenameLabelFmt(dst, target string) LabelFmt {
   214  	return LabelFmt{
   215  		Name:   dst,
   216  		Rename: true,
   217  		Value:  target,
   218  	}
   219  }
   220  
   221  // NewTemplateLabelFmt creates a configuration to format a label using text template.
   222  func NewTemplateLabelFmt(dst, template string) LabelFmt {
   223  	return LabelFmt{
   224  		Name:   dst,
   225  		Rename: false,
   226  		Value:  template,
   227  	}
   228  }
   229  
   230  type labelFormatter struct {
   231  	tmpl *template.Template
   232  	LabelFmt
   233  }
   234  
   235  type LabelsFormatter struct {
   236  	formats []labelFormatter
   237  	buf     *bytes.Buffer
   238  }
   239  
   240  // NewLabelsFormatter creates a new formatter that can format multiple labels at once.
   241  // Either by renaming or using text template.
   242  // It is not allowed to reformat the same label twice within the same formatter.
   243  func NewLabelsFormatter(fmts []LabelFmt) (*LabelsFormatter, error) {
   244  	if err := validate(fmts); err != nil {
   245  		return nil, err
   246  	}
   247  	formats := make([]labelFormatter, 0, len(fmts))
   248  
   249  	for _, fm := range fmts {
   250  		toAdd := labelFormatter{LabelFmt: fm}
   251  		if !fm.Rename {
   252  			t, err := template.New("label").Option("missingkey=zero").Funcs(functionMap).Parse(fm.Value)
   253  			if err != nil {
   254  				return nil, fmt.Errorf("invalid template for label '%s': %s", fm.Name, err)
   255  			}
   256  			toAdd.tmpl = t
   257  		}
   258  		formats = append(formats, toAdd)
   259  	}
   260  	return &LabelsFormatter{
   261  		formats: formats,
   262  		buf:     bytes.NewBuffer(make([]byte, 1024)),
   263  	}, nil
   264  }
   265  
   266  func validate(fmts []LabelFmt) error {
   267  	// it would be too confusing to rename and change the same label value.
   268  	// To avoid confusion we allow to have a label name only once per stage.
   269  	uniqueLabelName := map[string]struct{}{}
   270  	for _, f := range fmts {
   271  		if f.Name == logqlmodel.ErrorLabel {
   272  			return fmt.Errorf("%s cannot be formatted", f.Name)
   273  		}
   274  		if _, ok := uniqueLabelName[f.Name]; ok {
   275  			return fmt.Errorf("multiple label name '%s' not allowed in a single format operation", f.Name)
   276  		}
   277  		uniqueLabelName[f.Name] = struct{}{}
   278  	}
   279  	return nil
   280  }
   281  
   282  func (lf *LabelsFormatter) Process(_ int64, l []byte, lbs *LabelsBuilder) ([]byte, bool) {
   283  	var data interface{}
   284  	for _, f := range lf.formats {
   285  		if f.Rename {
   286  			v, ok := lbs.Get(f.Value)
   287  			if ok {
   288  				lbs.Set(f.Name, v)
   289  				lbs.Del(f.Value)
   290  			}
   291  			continue
   292  		}
   293  		lf.buf.Reset()
   294  		if data == nil {
   295  			data = lbs.Map()
   296  		}
   297  		if err := f.tmpl.Execute(lf.buf, data); err != nil {
   298  			lbs.SetErr(errTemplateFormat)
   299  			lbs.SetErrorDetails(err.Error())
   300  			continue
   301  		}
   302  		lbs.Set(f.Name, lf.buf.String())
   303  	}
   304  	return l, true
   305  }
   306  
   307  func (lf *LabelsFormatter) RequiredLabelNames() []string {
   308  	var names []string
   309  	for _, fm := range lf.formats {
   310  		if fm.Rename {
   311  			names = append(names, fm.Value)
   312  			continue
   313  		}
   314  		names = append(names, listNodeFields([]parse.Node{fm.tmpl.Root})...)
   315  	}
   316  	return uniqueString(names)
   317  }
   318  
   319  func trunc(c int, s string) string {
   320  	runes := []rune(s)
   321  	l := len(runes)
   322  	if c < 0 && l+c > 0 {
   323  		return string(runes[l+c:])
   324  	}
   325  	if c >= 0 && l > c {
   326  		return string(runes[:c])
   327  	}
   328  	return s
   329  }
   330  
   331  // substring creates a substring of the given string.
   332  //
   333  // If start is < 0, this calls string[:end].
   334  //
   335  // If start is >= 0 and end < 0 or end bigger than s length, this calls string[start:]
   336  //
   337  // Otherwise, this calls string[start, end].
   338  func substring(start, end int, s string) string {
   339  	runes := []rune(s)
   340  	l := len(runes)
   341  	if end > l {
   342  		end = l
   343  	}
   344  	if start > l {
   345  		start = l
   346  	}
   347  	if start < 0 {
   348  		if end < 0 {
   349  			return ""
   350  		}
   351  		return string(runes[:end])
   352  	}
   353  	if end < 0 {
   354  		return string(runes[start:])
   355  	}
   356  	if start > end {
   357  		return ""
   358  	}
   359  	return string(runes[start:end])
   360  }