1 Star 0 Fork 0

peter / fabric

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
克隆/下载
table.go 8.69 KB
一键复制 编辑 原始数据 按行查看 历史
/*
Copyright IBM Corp. All Rights Reserved.
SPDX-License-Identifier: Apache-2.0
*/
package gendoc
import (
"bytes"
"fmt"
"io"
"sort"
"strings"
"github.com/hyperledger/fabric/common/metrics"
"github.com/hyperledger/fabric/common/metrics/internal/namer"
)
// A Field represents data that is included in the reference table for metrics.
type Field uint8
const (
Name Field = iota // Name is the meter name.
Type // Type is the type of meter option.
Description // Description is the help text from the meter option.
Labels // Labels is the meter's label information.
Bucket // Bucket is the statsd bucket format
)
// A Column represents a column of data in the reference table.
type Column struct {
Field Field
Name string
Split int
Width int
}
// NewPrometheusTable creates a table that can be used to document Prometheus
// metrics maintained by Fabric.
func NewPrometheusTable(cells Cells) Table {
labelSplit := 0
for _, cell := range cells {
for _, label := range cell.labels {
labelSplit = max(labelSplit, len(label)+2)
}
}
return Table{
Cells: cells,
Columns: []Column{
{Field: Name, Name: "Name", Width: max(cells.MaxLen(Name)+2, 20)},
{Field: Type, Name: "Type", Width: 11},
{Field: Description, Name: "Description", Width: 60},
{Field: Labels, Name: "Labels", Width: 80, Split: labelSplit},
},
}
}
// NewStatsdTable creates a table that can be used to document StatsD metrics
// maintained by Fabric.
func NewStatsdTable(cells Cells) Table {
return Table{
Cells: cells,
Columns: []Column{
{Field: Bucket, Name: "Bucket", Width: max(cells.MaxLen(Bucket)+2, 20)},
{Field: Type, Name: "Type", Width: 11},
{Field: Description, Name: "Description", Width: 60},
},
}
}
// A Table maintains the cells and columns used to generate the restructured text
// formatted reference documentation.
type Table struct {
Columns []Column
Cells Cells
}
// Generate generates a restructured text formatted table from the cells and
// columns contained in the table.
func (t Table) Generate(w io.Writer) {
fmt.Fprint(w, t.header())
for _, c := range t.Cells {
fmt.Fprint(w, t.formatCell(c))
fmt.Fprint(w, t.rowSeparator())
}
}
func (t Table) rowSeparator() string { return t.separator("-", false) }
func (t Table) headerSeparator() string { return t.separator("=", false) }
func (t Table) separator(delim string, firstLine bool) string {
var buf bytes.Buffer
for _, c := range t.Columns {
buf.WriteString("+")
if !firstLine && c.Split != 0 {
buf.WriteString(strings.Repeat(delim, c.Split))
buf.WriteString("+")
buf.WriteString(strings.Repeat(delim, c.Width-c.Split-1))
} else {
buf.WriteString(strings.Repeat(delim, c.Width))
}
}
buf.WriteString("+\n")
return buf.String()
}
func (t Table) header() string {
var h string
h += t.separator("-", true)
for _, c := range t.Columns {
h += "| " + printWidth(c.Name, c.Width-2, 0) + " "
}
h += "|\n"
h += t.headerSeparator()
return h
}
func (t Table) formatCell(cell Cell) string {
contents := map[Field][]string{}
lineCount := 0
// wrap lines
for _, c := range t.Columns {
if c.Split != 0 {
lines := formSubtableCell(cell.labels, cell.labelHelp, c.Split, c.Width)
if l := len(lines); l > lineCount {
lineCount = l
}
contents[c.Field] = lines
} else {
lines := wrapWidths(cell.Field(c.Field), c.Width-2)
if l := len(lines); l > lineCount {
lineCount = l
}
contents[c.Field] = lines
}
}
// add extra lines
for _, col := range t.Columns {
lines := contents[col.Field]
contents[col.Field] = padLines(lines, col.Width-2, lineCount, col.Split-1)
}
var c string
for i := 0; i < lineCount; i++ {
endSplit := "|"
endPadding := " "
for _, col := range t.Columns {
frontSplit := "| "
if contents[col.Field][i][0] == '+' {
frontSplit = ""
endSplit = ""
endPadding = ""
}
c += frontSplit + contents[col.Field][i] + endPadding
}
c += endSplit + "\n"
}
return c
}
func formSubtableCell(keys []string, m map[string]string, leftWidth, cellWidth int) []string {
var result []string
for i, key := range keys {
// build subtable separator
if i != 0 {
var buf bytes.Buffer
buf.WriteString("+")
buf.WriteString(strings.Repeat("-", leftWidth))
buf.WriteString("+")
buf.WriteString(strings.Repeat("-", cellWidth-leftWidth-1))
buf.WriteString("+")
result = append(result, buf.String())
}
// populate subtable
rightLines := wrapWidths(m[key], cellWidth-leftWidth-1)
leftLines := padLines([]string{key}, leftWidth-2, max(1, len(rightLines)), 0)
for i := 0; i < len(leftLines); i++ {
text := fmt.Sprintf("%s | %s", leftLines[i], rightLines[i])
result = append(result, text)
}
}
return result
}
func wrapWidths(s string, width int) []string {
var result []string
for _, s := range strings.Split(s, "\n") {
result = append(result, wrapWidth(s, width)...)
}
return result
}
func wrapWidth(s string, width int) []string {
words := strings.Fields(strings.TrimSpace(s))
if len(words) == 0 { // only white space
return []string{s}
}
result := words[0]
remaining := width - len(words[0])
for _, w := range words[1:] {
if len(w)+1 > remaining {
result += "\n" + w
remaining = width - len(w) - 1
} else {
result += " " + w
remaining -= len(w) + 1
}
}
return strings.Split(result, "\n")
}
func padLines(lines []string, w, h, split int) []string {
for len(lines) < h {
lines = append(lines, "")
}
for idx, line := range lines {
lines[idx] = printWidth(line, w, split)
}
return lines
}
func printWidth(s string, w, split int) string {
if len(s) < w {
var buf bytes.Buffer
buf.WriteString(s)
if split <= len(s) {
buf.WriteString(strings.Repeat(" ", w-len(s)))
} else {
buf.WriteString(strings.Repeat(" ", split-len(s)))
buf.WriteString("|")
buf.WriteString(strings.Repeat(" ", w-split-1))
}
s = buf.String()
}
return s
}
func max(x, y int) int {
if x > y {
return x
}
return y
}
type Cell struct {
meterType string
namer *namer.Namer
description string
labels []string
labelHelp map[string]string
}
func (c Cell) Field(f Field) string {
switch f {
case Name:
return c.Name()
case Type:
return c.Type()
case Description:
return c.Description()
case Labels:
return c.Labels()
case Bucket:
return c.BucketFormat()
default:
panic(fmt.Sprintf("unknown field type: %d", f))
}
}
func (c Cell) Name() string { return strings.Replace(c.namer.FullyQualifiedName(), ".", "_", -1) }
func (c Cell) Type() string { return c.meterType }
func (c Cell) Description() string { return c.description }
func (c Cell) Labels() string {
buf := &strings.Builder{}
for _, label := range c.labels {
fmt.Fprintf(buf, " | %s\n", label)
}
return strings.TrimRight(buf.String(), "\n")
}
func (c Cell) BucketFormat() string {
var lvs []string
for _, label := range c.labels {
lvs = append(lvs, label, asBucketVar(label))
}
return c.namer.Format(lvs...)
}
func asBucketVar(s string) string { return "%{" + s + "}" }
type Cells []Cell
func (c Cells) Len() int { return len(c) }
func (c Cells) Less(i, j int) bool { return c[i].Name() < c[j].Name() }
func (c Cells) Swap(i, j int) { c[i], c[j] = c[j], c[i] }
func (c Cells) MaxLen(f Field) int {
var maxlen int
for _, c := range c {
if l := len(c.Field(f)); l > maxlen {
maxlen = l
}
}
return maxlen
}
// NewCells transforms metrics options to cells that can be used for doc
// generation.
func NewCells(options []interface{}) (Cells, error) {
var cells Cells
for _, o := range options {
switch m := o.(type) {
case metrics.CounterOpts:
cells = append(cells, counterCell(m))
case metrics.GaugeOpts:
cells = append(cells, gaugeCell(m))
case metrics.HistogramOpts:
cells = append(cells, histogramCell(m))
default:
return nil, fmt.Errorf("unknown option type: %t", o)
}
}
sort.Sort(cells)
return cells, nil
}
func counterCell(c metrics.CounterOpts) Cell {
if c.StatsdFormat == "" {
c.StatsdFormat = "%{#fqname}"
}
return Cell{
namer: namer.NewCounterNamer(c),
meterType: "counter",
description: c.Help,
labels: c.LabelNames,
labelHelp: c.LabelHelp,
}
}
func gaugeCell(g metrics.GaugeOpts) Cell {
if g.StatsdFormat == "" {
g.StatsdFormat = "%{#fqname}"
}
return Cell{
namer: namer.NewGaugeNamer(g),
meterType: "gauge",
description: g.Help,
labels: g.LabelNames,
labelHelp: g.LabelHelp,
}
}
func histogramCell(h metrics.HistogramOpts) Cell {
if h.StatsdFormat == "" {
h.StatsdFormat = "%{#fqname}"
}
return Cell{
namer: namer.NewHistogramNamer(h),
meterType: "histogram",
description: h.Help,
labels: h.LabelNames,
labelHelp: h.LabelHelp,
}
}
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
1
https://gitee.com/peter_code_git/fabric.git
git@gitee.com:peter_code_git/fabric.git
peter_code_git
fabric
fabric
v2.1.0

搜索帮助

344bd9b3 5694891 D2dac590 5694891