Golang模板template


背景概述

当我们在进行json字段选取以及渲染时,我们经常会见到{{}},其实这就是我们今天要讲解的模板即是template。例如prometheusAlert中的模板就是使用了改语法。

必备技能

  1. 字段选取

    {{ . }} 表示json的所有域,例如:{"name":"anruo","age":18},我们使用{{ . }}就可以获取到所有的内容 {{ .name }} 就可以获取到anruo字符串。

    range: 循环,当json中有列表时,我们可以使用{{range $index,$value:=.xx}}{{$index,$value}}{{end}}来进行取值。

    {{-}}: 去重空格内容

  2. 自定义函数

    所谓自定义函数,即是我们可以自定义处理字段。例如:时间字段中的时区转换。

  3. 运算符

    eq: ==

    ge: >=

    gt: >

    le: <=

    lt: <

    ne: !=

案例演示

我们先模拟一下源数据,这里我们定义一个结构体

type Temp struct {
 Name  string
 Age   int64
 Like  []string
 Study []Study
}

type Study struct {
 Name string
       School string
}

初始化template

func NewTemplate(tmpl string) (*template.Template, error) {
 return template.New("anruo").Funcs(TmpFuncMap()).Parse(tmpl)
}

func TmpExcute(tmpl string, data interface{}) {
 t, _ := NewTemplate(tmpl)
 _ = t.Execute(os.Stdout, data)
}

func TmpFuncMap() template.FuncMap {
 return template.FuncMap{
  "GetLocalTime": func() string { return time.Now().String() },
  "SubTime": func(oldTime string) string {
   t1, _ := time.Parse("2006-01-02 15:04:05", oldTime)
   t2, _ := time.Parse("2006-01-02 15:04:05", time.Now().Format("2006-01-02 15:04:05"))
   return t2.Sub(t1).String()
  },
 }
}

这里我们使用了自定义函数,当然这是我们模拟使用的。

定义解析

姓名:{{- .Name}}
年龄:{{.Age}}
{{range $value := .Like}}
爱好:{{$value}}
{{end}}
{{range $value := .Study}}
学科:{{$value.Name}}
学校:{{$value.School}}
{{end}}
当前时间: {{GetLocalTime}}
时间差:{{SubTime "2024-09-09 15:04:05"}}

完整代码如下

package main

import (
 "html/template"
 "os"
 "time"
)

func main() {
 var temp = Temp{
  Name: "张三",
  Age:  18,
  Like: []string{"足球", "篮球"},
  Study: []Study{
   {Name: "语文", School: "铁岭小学"},
   {Name: "数学", School: "吉林中学"},
   {Name: "英语", School: "郑州大学"},
  },
 }
 tmpl := `
姓名:{{- .Name}}
年龄:{{.Age}}
{{range $value := .Like}}
爱好:{{$value}}
{{end}}
{{range $value := .Study}}
学科:{{$value.Name}}
学校:{{$value.School}}
{{end}}
当前时间: {{GetLocalTime}}
时间差:{{SubTime "2024-09-09 15:04:05"}}
`
 TmpExcute(tmpl, temp)
}

func NewTemplate(tmpl string) (*template.Template, error) {
 return template.New("anruo").Funcs(TmpFuncMap()).Parse(tmpl)
}

func TmpExcute(tmpl string, data interface{}) {
 t, _ := NewTemplate(tmpl)
 _ = t.Execute(os.Stdout, data)
}

func TmpFuncMap() template.FuncMap {
 return template.FuncMap{
  "GetLocalTime": func() string { return time.Now().String() },
  "SubTime": func(oldTime string) string {
   t1, _ := time.Parse("2006-01-02 15:04:05", oldTime)
   t2, _ := time.Parse("2006-01-02 15:04:05", time.Now().Format("2006-01-02 15:04:05"))
   return t2.Sub(t1).String()
  },
 }
}

type Temp struct {
 Name  string
 Age   int64
 Like  []string
 Study []Study
}

type Study struct {
 Name   string
 School string
}

运行结果为:

姓名:张三 年龄:18

爱好:足球

爱好:篮球

学科:语文 学校:铁岭小学

学科:数学 学校:吉林中学

学科:英语 学校:郑州大学

当前时间: 2024-09-09 16:48:40.7547471 +0800 CST m=+0.005393101 时间差:1h44m35s

图片image-20240910164257362

我们可以发现是有空行的,那么我们可以使用我们-来取消空行

姓名:{{- .Name}}
年龄:{{.Age}}
{{range $value := .Like -}}
爱好:{{$value}}
{{end}}
{{- range $value := .Study -}}
学科:{{$value.Name}}
学校:{{$value.School}}
{{end -}}
当前时间: {{GetLocalTime}}
时间差:{{SubTime "2024-09-09 15:04:05"}}

运行结果为:

图片image-20240910164306692

我们可以发现,其中学科和学校是单独的行,如果我们要进行合并呢

姓名:{{- .Name}}
年龄:{{.Age}}
{{range $value := .Like -}}
爱好:{{$value}}
{{end -}}
学科:{{range $index, $value := .Study}}{{if $index}}, {{end}}{{$value.Name}}{{end}}
学校:{{range $index, $value := .Study}}{{if $index}}, {{end}}{{$value.School}}{{end}}
当前时间: {{GetLocalTime}}
时间差:{{SubTime "2024-09-09 15:04:05" -}}

我们可以使用字符串拼接的方式,当然我们也可以使用自定义函数来进行。

看一个if判断的模板

姓名:{{- .Name}}
{{- if eq .Age 19}}
年龄:{{.Age}}
{{else}}
年龄:{{.Age}}+
{{end -}}
{{range $value := .Like -}}
爱好:{{$value}}
{{end -}}
学科:{{range $index, $value := .Study}}{{if $index}}, {{end}}{{$value.Name}}{{end}}
学校:{{range $index, $value := .Study}}{{if $index}}, {{end}}{{$value.School}}{{end}}
当前时间: {{GetLocalTime}}
时间差:{{SubTime "2024-09-09 15:04:05" -}}

这里我们使用了Age进行判断,其结果为:

图片image-20240910164118887

告警数据

我们这里以prometheus的告警数据为例,来简单说明一下template的用法

告警源数据

{
  "receiver": "webhook-zja",
  "status": "firing",
  "alerts": [
    {
      "status": "firing",
      "labels": {
        "alertname": "服务线程数超过1500",
        "container": "data-center",
        "namespace": "bigdata",
        "severity": "warning"
      },
      "annotations": {
        "description": "bigdata data-center 线程数超过1500!!当前值1.629k% ",
        "summary": "bigdata data-center 线程数超过1500!"
      },
      "startsAt": "2023-08-09T15:23:17.0967074Z",
      "endsAt": "0001-01-01T00:00:00Z",
      "fingerprint": "4e4b8a9d78edaacd"
    },
    {
      "status": "firing",
      "labels": {
        "alertname": "服务线程数超过1500",
        "container": "english-server",
        "namespace": "english",
        "severity": "warning"
      },
      "annotations": {
        "description": "english english-server 线程数超过1500!!当前值2.011k% ",
        "summary": "english english-server 线程数超过1500!"
      },
      "startsAt": "2023-08-10T06:35:17.0967074Z",
      "endsAt": "0001-01-01T00:00:00Z",
      "fingerprint": "16e2c7f3733ec786"
    },
    {
      "status": "firing",
      "labels": {
        "alertname": "服务线程数超过1500",
        "container": "english-web",
        "namespace": "english",
        "severity": "warning"
      },
      "annotations": {
        "description": "english english-web 线程数超过1500!!当前值2.51k% ",
        "summary": "english english-web 线程数超过1500!"
      },
      "startsAt": "2023-08-10T06:24:17.0967074Z",
      "endsAt": "0001-01-01T00:00:00Z",
      "fingerprint": "259577587fd712fb"
    },
    {
      "status": "firing",
      "labels": {
        "alertname": "服务线程数超过1500",
        "container": "english-web2",
        "namespace": "english",
        "severity": "warning"
      },
      "annotations": {
        "description": "english english-web2 线程数超过1500!!当前值1.541k%",
        "summary": "english english-web2 线程数超过1500!"
      },
      "startsAt": "2023-08-10T07:35:17.0967074Z",
      "endsAt": "0001-01-01T00:00:00Z",
      "fingerprint": "fd899e29b5a3d4a8"
    }
  ],
  "groupLabels": {
    "alertname": "服务线程数超过1500"
  },
  "commonLabels": {
    "alertname": "服务线程数超过1500",
    "severity": "warning"
  },
  "commonAnnotations": {},
  "externalURL": "http://kube-prometheus-alertmanager.monitoring:9093",
  "version": "4",
  "groupKey": "{}:{alertname=\"服务线程数超过1500\"}",
  "truncatedAlerts": 0
}

模板

{{- $alertDesc := "" -}}
{{- range $k, $v := .alerts -}}
  {{- if eq $k 0 -}}
    {{- $alertDesc = $v.annotations.description -}}
  {{- end -}}
{{- end -}}
告警名称:{{.groupLabels.alertname}}
告警服务: {{ range $k,$v:=.alerts }}{{if $k}},{{end}}{{$v.labels.container}}{{if $v.labels.namespace}}({{$v.labels.namespace}}){{end}}{{end}}
告警描述:{{$alertDesc}}

结果为:

告警名称:服务线程数超过1500

告警服务: data-center-point-server(bigdata-prod),english-parent-web(english-prod),english-student-web(english-prod),english-student-web3(english-prod)

告警描述:bigdata-prod data-center-point-server 线程数超过1500!!当前值1.629k%

总结

到此我们template就大致结束了,当我们在进行程序开发时,我们可以利用该包进行一些模板的渲染,例如Go+Ansible+Nginx的实现即是利用了该包,还有prometheusAlert也是如此。

posted @ 2024-10-11 15:51  技术颜良  阅读(22)  评论(0编辑  收藏  举报