github.com/pyroscope-io/pyroscope@v0.37.3-0.20230725203016-5f6947968bd0/benchmark/internal/cireport/metareport.go (about)

     1  package cireport
     2  
     3  import (
     4  	"fmt"
     5  	"strings"
     6  	"text/template"
     7  
     8  	"github.com/sirupsen/logrus"
     9  )
    10  
    11  type MetaReport struct {
    12  	allowlist map[string]bool
    13  }
    14  
    15  // NewMetaReport creates a meta report
    16  // the allowlist parameter refers to which keys are valid
    17  func NewMetaReport(allowlist []string) (*MetaReport, error) {
    18  	if len(allowlist) <= 0 {
    19  		return nil, fmt.Errorf("at least one item should be allowed")
    20  	}
    21  
    22  	a := make(map[string]bool)
    23  	for _, v := range allowlist {
    24  		a[v] = true
    25  	}
    26  
    27  	return &MetaReport{
    28  		allowlist: a,
    29  	}, nil
    30  }
    31  
    32  type meta struct {
    33  	Key string
    34  	Val string
    35  }
    36  
    37  // Report generates a markdown report
    38  func (mr *MetaReport) Report(title string, vars []string) (string, error) {
    39  	if len(vars) <= 0 {
    40  		return "", fmt.Errorf("at least one item should be reported")
    41  	}
    42  
    43  	// transform 'A=B' into {key: A, val: B}
    44  	m := make([]meta, 0, len(vars))
    45  	for _, v := range vars {
    46  		key, val, err := mr.breakOnEqual(v)
    47  		logrus.Debugf("breaking string %s on '=' produces key %s value %s\n", v, key, val)
    48  		if err != nil {
    49  			return "", err
    50  		}
    51  
    52  		n := meta{key, val}
    53  		m = append(m, n)
    54  	}
    55  
    56  	// validate it's in the allowlist
    57  	logrus.Debug("validating there're no values not in the allowlist")
    58  	err := mr.validate(m)
    59  	if err != nil {
    60  		return "", err
    61  	}
    62  
    63  	logrus.Debug("generating template")
    64  	report, err := mr.tpl(title, m)
    65  	if err != nil {
    66  		return "", err
    67  	}
    68  
    69  	return report, nil
    70  }
    71  
    72  func (*MetaReport) breakOnEqual(s string) (key string, value string, err error) {
    73  	split := strings.Split(s, "=")
    74  	if len(split) != 2 {
    75  		return "", "", fmt.Errorf("expect value in format A=B")
    76  	}
    77  
    78  	if split[0] == "" || split[1] == "" {
    79  		return "", "", fmt.Errorf("expect non empty key/value")
    80  	}
    81  
    82  	return split[0], split[1], nil
    83  }
    84  
    85  func (mr *MetaReport) validate(m []meta) error {
    86  	for _, v := range m {
    87  		if _, ok := mr.allowlist[v.Key]; !ok {
    88  			return fmt.Errorf("key is not allowed: '%s'", v.Key)
    89  		}
    90  	}
    91  
    92  	return nil
    93  }
    94  
    95  func (*MetaReport) tpl(title string, m []meta) (string, error) {
    96  	var tpl strings.Builder
    97  
    98  	data := struct {
    99  		Title string
   100  		Meta  []meta
   101  	}{
   102  		Title: title,
   103  		Meta:  m,
   104  	}
   105  	t, err := template.New("meta-report.gotpl").
   106  		ParseFS(resources, "resources/meta-report.gotpl")
   107  
   108  	if err != nil {
   109  		return "", err
   110  	}
   111  
   112  	if err := t.Execute(&tpl, data); err != nil {
   113  		return "", err
   114  	}
   115  
   116  	return tpl.String(), nil
   117  }