没有足够的数据
(゚∀゚ )
暂时没有任何数据
mojotv_cn 收藏了文章 · 2020-07-19
不废话,
Golang 日志查看疼点
我们可以使用logrus hook 快速的输出日志到Elastic Search 在使用Chrome Elastic Search GUI插件快速的定位你想用的日志.
docker run -d --name es.dev -p 9201:9200 -p 9301:9300 -e "discovery.type=single-node" elastic/elasticsearch:6.7.1
你可以去网上搜搜索 es数据库安装,在本教程中我们就来安装一个 docker es 单节点 (处理golang日志性能足够)
docker pull elasticsearch:6.7.0
docker run -d --name mojocn.es -p 9201:9200 -p 9301:9300 -e "discovery.type=single-node" elastic/elasticsearch:6.7.1
这样就您就启动了一个 名字为 mojocn.es 端口 9201的单节点数据库.
main.go 完整代码: https://github.com/mojocn/eslogrushook
package main
import (
"context"
"fmt"
"github.com/olivere/elastic"
"github.com/sirupsen/logrus"
"log"
"os"
"strings"
"time"
)
//cfg 配置文件
type cfg struct {
LogLvl string // 日志级别
EsAddrs []string //ES addr
EsUser string //ES user
EsPassword string //ES password
}
//setupLogrus 初始化logrus 同时把logrus的logger var 引用到这个common.Logger
func setupLogrus(cc cfg) error {
//logFileName := fmt.Sprintf("%s_%s.log", os.Args[1], time.Now().Format("06_01_02T15_04_05"))
//
//f, err := os.Create(logFileName)
//if err != nil {
// return err
//}
logLvl, err := logrus.ParseLevel(cc.LogLvl)
if err != nil {
return err
}
logrus.SetLevel(logLvl)
//logrus.SetReportCaller(true)
//logrus.SetFormatter(&logrus.JSONFormatter{})
//使用console默认输出
//logrus.SetOutput(f)
logrus.SetReportCaller(true)
//开启 logrus ES hook
esh := newEsHook(cc)
logrus.AddHook(esh)
fmt.Printf(">= error 级别,查看日志 %#v 中的logrus* 索引\n", cc.EsAddrs)
return nil
}
func main() {
cc := cfg{
LogLvl: "error",
EsAddrs: []string{"http://es.felix.mojotv.cn:9202/"},
EsUser: "",
EsPassword: "",
}
err := setupLogrus(cc)
if err != nil {
log.Fatal(err)
}
logrus.WithField("URI", "mojotv.cn").Error("I love my son Felix")
//等待日志发送到ES
time.Sleep(time.Second * 10)
}
//esHook 自定义的ES hook
type esHook struct {
cmd string // 记录启动的命令
client *elastic.Client
}
//newEsHook 初始化
func newEsHook(cc cfg) *esHook {
es, err := elastic.NewClient(
elastic.SetURL(cc.EsAddrs...),
elastic.SetBasicAuth(cc.EsUser, cc.EsPassword),
elastic.SetSniff(false),
elastic.SetHealthcheckInterval(15*time.Second),
elastic.SetErrorLog(log.New(os.Stderr, "ES:", log.LstdFlags)),
//elastic.SetInfoLog(log.New(os.Stdout, "ES:", log.LstdFlags)),
)
if err != nil {
log.Fatal("failed to create Elastic V6 Client: ", err)
}
return &esHook{client: es, cmd: strings.Join(os.Args, " ")}
}
//Fire logrus hook interface 方法
func (hook *esHook) Fire(entry *logrus.Entry) error {
doc := newEsLog(entry)
doc["cmd"] = hook.cmd
go hook.sendEs(doc)
return nil
}
//Levels logrus hook interface 方法
func (hook *esHook) Levels() []logrus.Level {
return []logrus.Level{
logrus.PanicLevel,
logrus.FatalLevel,
logrus.ErrorLevel,
}
}
//sendEs 异步发送日志到es
func (hook *esHook) sendEs(doc appLogDocModel) {
defer func() {
if r := recover(); r != nil {
fmt.Println("send entry to es failed: ", r)
}
}()
_, err := hook.client.Index().Index(doc.indexName()).Type("_doc").BodyJson(doc).Do(context.Background())
if err != nil {
log.Println(err)
}
}
//appLogDocModel es model
type appLogDocModel map[string]interface{}
func newEsLog(e *logrus.Entry) appLogDocModel {
ins := map[string]interface{}{}
for kk, vv := range e.Data {
ins[kk] = vv
}
ins["time"] = time.Now().Local()
ins["lvl"] = e.Level
ins["message"] = e.Message
ins["caller"] = fmt.Sprintf("%s:%d %#v", e.Caller.File, e.Caller.Line, e.Caller.Func)
return ins
}
// indexName es index name 时间分割
func (m *appLogDocModel) indexName() string {
return "mojocn-cn-" + time.Now().Local().Format("2006-01-02")
}
go run main.go 日志输出
>= error 级别,查看日志 []string{"http://i.love.mojotv.cn:9202/"} 中的logrus* 索引
time="2020-07-17T17:26:03+08:00" level=error msg=lld func=main.main file="D:/GolandProjects/logrusEsHook/main.go:59" URI=mojotv.cn
0. 原文地址: [链接]1. 背景不废话,Golang 日志查看疼点linux查看日志,一般开发者对linux命令不是很熟悉, 搜索日志更加难上加难JAVA生态 ELKB 日志收集搭建复杂,需要的是一个快速查看搜索,客户端来搜索日志1.1 前期准备我们可以使用logrus hook 快速的输出日志到Elas...
mojotv_cn 发布了文章 · 2020-07-17
不废话,
Golang 日志查看疼点
我们可以使用logrus hook 快速的输出日志到Elastic Search 在使用Chrome Elastic Search GUI插件快速的定位你想用的日志.
docker run -d --name es.dev -p 9201:9200 -p 9301:9300 -e "discovery.type=single-node" elastic/elasticsearch:6.7.1
你可以去网上搜搜索 es数据库安装,在本教程中我们就来安装一个 docker es 单节点 (处理golang日志性能足够)
docker pull elasticsearch:6.7.0
docker run -d --name mojocn.es -p 9201:9200 -p 9301:9300 -e "discovery.type=single-node" elastic/elasticsearch:6.7.1
这样就您就启动了一个 名字为 mojocn.es 端口 9201的单节点数据库.
main.go 完整代码: https://github.com/mojocn/eslogrushook
package main
import (
"context"
"fmt"
"github.com/olivere/elastic"
"github.com/sirupsen/logrus"
"log"
"os"
"strings"
"time"
)
//cfg 配置文件
type cfg struct {
LogLvl string // 日志级别
EsAddrs []string //ES addr
EsUser string //ES user
EsPassword string //ES password
}
//setupLogrus 初始化logrus 同时把logrus的logger var 引用到这个common.Logger
func setupLogrus(cc cfg) error {
//logFileName := fmt.Sprintf("%s_%s.log", os.Args[1], time.Now().Format("06_01_02T15_04_05"))
//
//f, err := os.Create(logFileName)
//if err != nil {
// return err
//}
logLvl, err := logrus.ParseLevel(cc.LogLvl)
if err != nil {
return err
}
logrus.SetLevel(logLvl)
//logrus.SetReportCaller(true)
//logrus.SetFormatter(&logrus.JSONFormatter{})
//使用console默认输出
//logrus.SetOutput(f)
logrus.SetReportCaller(true)
//开启 logrus ES hook
esh := newEsHook(cc)
logrus.AddHook(esh)
fmt.Printf(">= error 级别,查看日志 %#v 中的logrus* 索引\n", cc.EsAddrs)
return nil
}
func main() {
cc := cfg{
LogLvl: "error",
EsAddrs: []string{"http://es.felix.mojotv.cn:9202/"},
EsUser: "",
EsPassword: "",
}
err := setupLogrus(cc)
if err != nil {
log.Fatal(err)
}
logrus.WithField("URI", "mojotv.cn").Error("I love my son Felix")
//等待日志发送到ES
time.Sleep(time.Second * 10)
}
//esHook 自定义的ES hook
type esHook struct {
cmd string // 记录启动的命令
client *elastic.Client
}
//newEsHook 初始化
func newEsHook(cc cfg) *esHook {
es, err := elastic.NewClient(
elastic.SetURL(cc.EsAddrs...),
elastic.SetBasicAuth(cc.EsUser, cc.EsPassword),
elastic.SetSniff(false),
elastic.SetHealthcheckInterval(15*time.Second),
elastic.SetErrorLog(log.New(os.Stderr, "ES:", log.LstdFlags)),
//elastic.SetInfoLog(log.New(os.Stdout, "ES:", log.LstdFlags)),
)
if err != nil {
log.Fatal("failed to create Elastic V6 Client: ", err)
}
return &esHook{client: es, cmd: strings.Join(os.Args, " ")}
}
//Fire logrus hook interface 方法
func (hook *esHook) Fire(entry *logrus.Entry) error {
doc := newEsLog(entry)
doc["cmd"] = hook.cmd
go hook.sendEs(doc)
return nil
}
//Levels logrus hook interface 方法
func (hook *esHook) Levels() []logrus.Level {
return []logrus.Level{
logrus.PanicLevel,
logrus.FatalLevel,
logrus.ErrorLevel,
}
}
//sendEs 异步发送日志到es
func (hook *esHook) sendEs(doc appLogDocModel) {
defer func() {
if r := recover(); r != nil {
fmt.Println("send entry to es failed: ", r)
}
}()
_, err := hook.client.Index().Index(doc.indexName()).Type("_doc").BodyJson(doc).Do(context.Background())
if err != nil {
log.Println(err)
}
}
//appLogDocModel es model
type appLogDocModel map[string]interface{}
func newEsLog(e *logrus.Entry) appLogDocModel {
ins := map[string]interface{}{}
for kk, vv := range e.Data {
ins[kk] = vv
}
ins["time"] = time.Now().Local()
ins["lvl"] = e.Level
ins["message"] = e.Message
ins["caller"] = fmt.Sprintf("%s:%d %#v", e.Caller.File, e.Caller.Line, e.Caller.Func)
return ins
}
// indexName es index name 时间分割
func (m *appLogDocModel) indexName() string {
return "mojocn-cn-" + time.Now().Local().Format("2006-01-02")
}
go run main.go 日志输出
>= error 级别,查看日志 []string{"http://i.love.mojotv.cn:9202/"} 中的logrus* 索引
time="2020-07-17T17:26:03+08:00" level=error msg=lld func=main.main file="D:/GolandProjects/logrusEsHook/main.go:59" URI=mojotv.cn
0. 原文地址: [链接]1. 背景不废话,Golang 日志查看疼点linux查看日志,一般开发者对linux命令不是很熟悉, 搜索日志更加难上加难JAVA生态 ELKB 日志收集搭建复杂,需要的是一个快速查看搜索,客户端来搜索日志1.1 前期准备我们可以使用logrus hook 快速的输出日志到Elas...
赞 1 收藏 1 评论 0
mojotv_cn 收藏了文章 · 2020-01-14
双重认证(英语:Two-factor authentication,缩写为2FA), 又译为双重验证、双因子认证、双因素认证、二元认证,又称两步骤验证(2-Step Verification,又译两步验证), 是一种认证方法,使用两种不同的元素,合并在一起,来确认用户的身份,是多因素验证中的一个特例.
TOTP 的全称是”基于时间的一次性密码”(Time-based One-time Password). 它是公认的可靠解决方案,已经写入国际标准 RFC6238.
它的步骤如下.
根据RFC 6238标准,供参考的实现如下:
生成一次性密码的伪代码
function GoogleAuthenticatorCode(string secret)
key := base32decode(secret)
message := floor(current Unix time / 30)
hash := HMAC-SHA1(key, message)
offset := last nibble of hash
truncatedHash := hash[offset..offset+3] //4 bytes starting at the offset
Set the first bit of truncatedHash to zero //remove the most significant bit
code := truncatedHash mod 1000000
pad code with 0 until length of code is 6
return code
生成事件性或计数性的一次性密码伪代码
function GoogleAuthenticatorCode(string secret)
key := base32decode(secret)
message := counter encoded on 8 bytes
hash := HMAC-SHA1(key, message)
offset := last nibble of hash
truncatedHash := hash[offset..offset+3] //4 bytes starting at the offset
Set the first bit of truncatedHash to zero //remove the most significant bit
code := truncatedHash mod 1000000
pad code with 0 until length of code is 6
return code
package main
import (
"crypto/hmac"
"crypto/sha1"
"encoding/binary"
"fmt"
"time"
)
func main() {
key := []byte("MOJOTV_CN_IS_AWESOME_AND_AWESOME_SECRET_KEY")
number := totp(key, time.Now(), 6)
fmt.Println("2FA code: ",number)
}
func hotp(key []byte, counter uint64, digits int) int {
//RFC 6238
h := hmac.New(sha1.New, key)
binary.Write(h, binary.BigEndian, counter)
sum := h.Sum(nil)
//取sha1的最后4byte
//0x7FFFFFFF 是long int的最大值
//math.MaxUint32 == 2^32-1
//& 0x7FFFFFFF == 2^31 Set the first bit of truncatedHash to zero //remove the most significant bit
// len(sum)-1]&0x0F 最后 像登陆 (bytes.len-4)
//取sha1 bytes的最后4byte 转换成 uint32
v := binary.BigEndian.Uint32(sum[sum[len(sum)-1]&0x0F:]) & 0x7FFFFFFF
d := uint32(1)
//取十进制的余数
for i := 0; i < digits && i < 8; i++ {
d *= 10
}
return int(v % d)
}
func totp(key []byte, t time.Time, digits int) int {
return hotp(key, uint64(t.Unix())/30, digits)
//return hotp(key, uint64(t.UnixNano())/30e9, digits)
}
双重认证(英语:Two-factor authentication,缩写为2FA), 又译为双重验证、双因子认证、双因素认证、二元认证,又称两步骤验证(2-Step Verification,又译两步验证), 是一种认证方法,使用两种不同的元素,合并在一起,来确认用户的身份,是多因素验证中的一个特例.
mojotv_cn 发布了文章 · 2020-01-14
双重认证(英语:Two-factor authentication,缩写为2FA), 又译为双重验证、双因子认证、双因素认证、二元认证,又称两步骤验证(2-Step Verification,又译两步验证), 是一种认证方法,使用两种不同的元素,合并在一起,来确认用户的身份,是多因素验证中的一个特例.
TOTP 的全称是”基于时间的一次性密码”(Time-based One-time Password). 它是公认的可靠解决方案,已经写入国际标准 RFC6238.
它的步骤如下.
根据RFC 6238标准,供参考的实现如下:
生成一次性密码的伪代码
function GoogleAuthenticatorCode(string secret)
key := base32decode(secret)
message := floor(current Unix time / 30)
hash := HMAC-SHA1(key, message)
offset := last nibble of hash
truncatedHash := hash[offset..offset+3] //4 bytes starting at the offset
Set the first bit of truncatedHash to zero //remove the most significant bit
code := truncatedHash mod 1000000
pad code with 0 until length of code is 6
return code
生成事件性或计数性的一次性密码伪代码
function GoogleAuthenticatorCode(string secret)
key := base32decode(secret)
message := counter encoded on 8 bytes
hash := HMAC-SHA1(key, message)
offset := last nibble of hash
truncatedHash := hash[offset..offset+3] //4 bytes starting at the offset
Set the first bit of truncatedHash to zero //remove the most significant bit
code := truncatedHash mod 1000000
pad code with 0 until length of code is 6
return code
package main
import (
"crypto/hmac"
"crypto/sha1"
"encoding/binary"
"fmt"
"time"
)
func main() {
key := []byte("MOJOTV_CN_IS_AWESOME_AND_AWESOME_SECRET_KEY")
number := totp(key, time.Now(), 6)
fmt.Println("2FA code: ",number)
}
func hotp(key []byte, counter uint64, digits int) int {
//RFC 6238
h := hmac.New(sha1.New, key)
binary.Write(h, binary.BigEndian, counter)
sum := h.Sum(nil)
//取sha1的最后4byte
//0x7FFFFFFF 是long int的最大值
//math.MaxUint32 == 2^32-1
//& 0x7FFFFFFF == 2^31 Set the first bit of truncatedHash to zero //remove the most significant bit
// len(sum)-1]&0x0F 最后 像登陆 (bytes.len-4)
//取sha1 bytes的最后4byte 转换成 uint32
v := binary.BigEndian.Uint32(sum[sum[len(sum)-1]&0x0F:]) & 0x7FFFFFFF
d := uint32(1)
//取十进制的余数
for i := 0; i < digits && i < 8; i++ {
d *= 10
}
return int(v % d)
}
func totp(key []byte, t time.Time, digits int) int {
return hotp(key, uint64(t.Unix())/30, digits)
//return hotp(key, uint64(t.UnixNano())/30e9, digits)
}
双重认证(英语:Two-factor authentication,缩写为2FA), 又译为双重验证、双因子认证、双因素认证、二元认证,又称两步骤验证(2-Step Verification,又译两步验证), 是一种认证方法,使用两种不同的元素,合并在一起,来确认用户的身份,是多因素验证中的一个特例.
赞 1 收藏 1 评论 0
mojotv_cn 收藏了文章 · 2020-01-14
我有很多行日志数据单行的格式是这样的
HOST;000012000629948340196501;ipv4;3; ips: user_id=2;user_name=172.21.1.102;policy_id=1;src_mac=52:54:00:62:7f:4a;dst_mac=58:69:6c:7b:fa:e7;src_ip=172.21.1.102;dst_ip=172.22.2.3;src_port=48612;dst_port=80;app_name=网页浏览(HTTP);protocol=TCP;app_protocol=HTTP;event_id=1310909;event_name=Microsoft_IIS_5.1_Frontpage扩展路径信息漏洞;event_type=安全漏洞;level=info;ctime=2019-12-26 11:17:17;action=pass
其中ips:
之前的都是不规范的字段
我需要把他解析成结构化的数据,这样的
type IpsItem struct {
UserId int `json:"user_id"`
UserName string `json:"user_name"`
SrcIp string `json:"src_ip"`
DstIp string `json:"dst_ip"`
SrcPort int `json:"src_port"`
DstPort int `json:"dst_port"`
AppName string `json:"app_name"`
Protocol string `json:"protocol"`
AppProtocol string `json:"app_protocol"`
EventId int `json:"event_id"`
EventName string `json:"event_name"`
EventType string `json:"event_type"`
Level string `json:"level"`
Ctime string `json:"ctime"`
Action string `json:"action"`
}
如果上面日志文件是json就非常容易解决了. 因为golang 标准库使用的就是 reflect反射生成struct
.
所以我的思路也是使用reflect
反射实现字符串转换成结构化的数据,你也可以大致了解标准库json.Unmarshal的原理.
package main
import (
"fmt"
"reflect"
"strings"
)
var testRawString = "HOST;000012000629948340196501;ipv4;3; ips: user_id=2;user_name=172.21.1.102;policy_id=1;src_mac=52:54:00:62:7f:4a;dst_mac=58:69:6c:7b:fa:e7;src_ip=172.21.1.102;dst_ip=172.22.2.3;src_port=48612;dst_port=80;app_name=网页浏览(HTTP);protocol=TCP;app_protocol=HTTP;event_id=1311495;event_name=HTTP_Nikto_WEB漏洞扫描;event_type=安全扫描;level=warning;ctime=2019-12-26 11:17:17;action=pass"
type IpsItem struct {
UserId int `json:"user_id"`
UserName string `json:"user_name"`
SrcIp string `json:"src_ip"`
DstIp string `json:"dst_ip"`
SrcPort int `json:"src_port"`
DstPort int `json:"dst_port"`
AppName string `json:"app_name"`
Protocol string `json:"protocol"`
AppProtocol string `json:"app_protocol"`
EventId int `json:"event_id"`
EventName string `json:"event_name"`
EventType string `json:"event_type"`
Level string `json:"level"`
Ctime string `json:"ctime"`
Action string `json:"action"`
}
func NewIpsItem(raw string) *IpsItem {
//清除非法的字符
raw = strings.ReplaceAll(raw, ":", ";")
ins := IpsItem{}
t := reflect.TypeOf(ins)
//遍历结构体属性
for i := 0; i < t.NumField(); i++ {
//获取属性structField
sf := t.Field(i)
//属性名称
fieldName := sf.Name
//tag json的值
tagName := sf.Tag.Get("json")
//获取字段值
fieldValue := reflect.ValueOf(&ins).Elem().FieldByName(fieldName)
//属性的值 type
switch sf.Type.Name() {
case "int":
var someInt int64
scanValueFromString(raw, tagName, tagName+"=%d", &someInt)
//给属性赋值
fieldValue.SetInt(someInt)
//todo:: 支持更多类型
default:
var someString string
scanValueFromString(raw, tagName, tagName+"=%s", &someString)
////给属性赋值
fieldValue.SetString(someString)
}
}
return &ins
}
//scanValueFromString 字符串 字段的值
func scanValueFromString(raw string, tagJsonValue, format string, someV interface{}) {
for _, ss := range strings.Split(raw, ";") {
ele := strings.TrimSpace(ss)
if strings.HasPrefix(ele, tagJsonValue) {
fmt.Sscanf(ele, format, someV)
//n, err := fmt.Sscanf(ele, format, someV)
//fmt.Println(n, err)
return
}
}
}
func main() {
ii := NewIpsItem(testRawString)
fmt.Printf("%+v\n", ii)
}
1. 🎼 解决了什么 原文https://mojotv.cn/go/golang-reflect-string 我有很多行日志数据单行的格式是这样的 {代码...} 其中ips:之前的都是不规范的字段 我需要把他解析成结构化的数据,这样的 {代码...} 如果上面日志文件是json就非常容易解决了. 因为golang 标准库使...
mojotv_cn 发布了文章 · 2020-01-14
我有很多行日志数据单行的格式是这样的
HOST;000012000629948340196501;ipv4;3; ips: user_id=2;user_name=172.21.1.102;policy_id=1;src_mac=52:54:00:62:7f:4a;dst_mac=58:69:6c:7b:fa:e7;src_ip=172.21.1.102;dst_ip=172.22.2.3;src_port=48612;dst_port=80;app_name=网页浏览(HTTP);protocol=TCP;app_protocol=HTTP;event_id=1310909;event_name=Microsoft_IIS_5.1_Frontpage扩展路径信息漏洞;event_type=安全漏洞;level=info;ctime=2019-12-26 11:17:17;action=pass
其中ips:
之前的都是不规范的字段
我需要把他解析成结构化的数据,这样的
type IpsItem struct {
UserId int `json:"user_id"`
UserName string `json:"user_name"`
SrcIp string `json:"src_ip"`
DstIp string `json:"dst_ip"`
SrcPort int `json:"src_port"`
DstPort int `json:"dst_port"`
AppName string `json:"app_name"`
Protocol string `json:"protocol"`
AppProtocol string `json:"app_protocol"`
EventId int `json:"event_id"`
EventName string `json:"event_name"`
EventType string `json:"event_type"`
Level string `json:"level"`
Ctime string `json:"ctime"`
Action string `json:"action"`
}
如果上面日志文件是json就非常容易解决了. 因为golang 标准库使用的就是 reflect反射生成struct
.
所以我的思路也是使用reflect
反射实现字符串转换成结构化的数据,你也可以大致了解标准库json.Unmarshal的原理.
package main
import (
"fmt"
"reflect"
"strings"
)
var testRawString = "HOST;000012000629948340196501;ipv4;3; ips: user_id=2;user_name=172.21.1.102;policy_id=1;src_mac=52:54:00:62:7f:4a;dst_mac=58:69:6c:7b:fa:e7;src_ip=172.21.1.102;dst_ip=172.22.2.3;src_port=48612;dst_port=80;app_name=网页浏览(HTTP);protocol=TCP;app_protocol=HTTP;event_id=1311495;event_name=HTTP_Nikto_WEB漏洞扫描;event_type=安全扫描;level=warning;ctime=2019-12-26 11:17:17;action=pass"
type IpsItem struct {
UserId int `json:"user_id"`
UserName string `json:"user_name"`
SrcIp string `json:"src_ip"`
DstIp string `json:"dst_ip"`
SrcPort int `json:"src_port"`
DstPort int `json:"dst_port"`
AppName string `json:"app_name"`
Protocol string `json:"protocol"`
AppProtocol string `json:"app_protocol"`
EventId int `json:"event_id"`
EventName string `json:"event_name"`
EventType string `json:"event_type"`
Level string `json:"level"`
Ctime string `json:"ctime"`
Action string `json:"action"`
}
func NewIpsItem(raw string) *IpsItem {
//清除非法的字符
raw = strings.ReplaceAll(raw, ":", ";")
ins := IpsItem{}
t := reflect.TypeOf(ins)
//遍历结构体属性
for i := 0; i < t.NumField(); i++ {
//获取属性structField
sf := t.Field(i)
//属性名称
fieldName := sf.Name
//tag json的值
tagName := sf.Tag.Get("json")
//获取字段值
fieldValue := reflect.ValueOf(&ins).Elem().FieldByName(fieldName)
//属性的值 type
switch sf.Type.Name() {
case "int":
var someInt int64
scanValueFromString(raw, tagName, tagName+"=%d", &someInt)
//给属性赋值
fieldValue.SetInt(someInt)
//todo:: 支持更多类型
default:
var someString string
scanValueFromString(raw, tagName, tagName+"=%s", &someString)
////给属性赋值
fieldValue.SetString(someString)
}
}
return &ins
}
//scanValueFromString 字符串 字段的值
func scanValueFromString(raw string, tagJsonValue, format string, someV interface{}) {
for _, ss := range strings.Split(raw, ";") {
ele := strings.TrimSpace(ss)
if strings.HasPrefix(ele, tagJsonValue) {
fmt.Sscanf(ele, format, someV)
//n, err := fmt.Sscanf(ele, format, someV)
//fmt.Println(n, err)
return
}
}
}
func main() {
ii := NewIpsItem(testRawString)
fmt.Printf("%+v\n", ii)
}
1. 🎼 解决了什么 原文https://mojotv.cn/go/golang-reflect-string 我有很多行日志数据单行的格式是这样的 {代码...} 其中ips:之前的都是不规范的字段 我需要把他解析成结构化的数据,这样的 {代码...} 如果上面日志文件是json就非常容易解决了. 因为golang 标准库使...
赞 1 收藏 1 评论 0
mojotv_cn 收藏了文章 · 2020-01-10
之前发现了golang标准库中又两个rand软件包,开始非常想知道他们之间的差异.
math/rand
软件包可以用于简单的游戏,但不能用于真正的随机性。
math/rand
: 伪随机数生成器crypto/rand
: 加密安全的随机数生成器Rob Pike的代码
package main
import (
"fmt"
"math/rand"
"time"
)
func main() {
c := fanIn(boring("Joe"), boring("Ann"))
for i := 0; i < 10; i++ {
fmt.Println(<-c)
}
fmt.Println("You're both boring; I'm leaving.")
}
func boring(msg string) <-chan string {
c := make(chan string)
go func() {
for i := 0; ; i++ {
c <- fmt.Sprintf("%s %d", msg, i)
time.Sleep(time.Duration(rand.Intn(1e3)) * time.Millisecond)
}
}()
return c
}
// FAN IN
func fanIn(input1, input2 <-chan string) <-chan string {
c := make(chan string)
go func() {
for {
c <- <-input1
}
}()
go func() {
for {
c <- <-input2
}
}()
return c
}
实现伪随机数生成器。
随机数由源生成。顶级函数(例如Float64和Int)使用默认的共享源,该源在每次运行程序时都会产生确定的值序列。 如果每次运行需要不同的行为, 请使用种子函数初始化默认的源。 默认的Source可安全地供多个goroutine并发使用,但不是由NewSource创建的Source。
package main
import (
"fmt"
"math/rand"
"time"
)
func init(){
rand.Seed(time.Now().UTC().UnixNano())
}
func main() {
// launches 2 generators and the fanIn collector function
c := fanIn(genrt(), genrt())
for i := 0; i < 10000; i++ {
fmt.Println(<-c)
}
}
func fanIn(a <-chan int, b <-chan int) <-chan string {
c := make(chan string)
// launch collector from a to channel
go func() {
var count int
for {
count += <-a
c <- fmt.Sprintf("Tally of A is: %d", count)
}
}()
// launch collector from b to channel
go func() {
var count int
for {
count += <-b
c <- fmt.Sprintf("Tally of B is: %d", count)
}
}()
return c
}
func genrt() <-chan int {
c := make(chan int)
// launch generator of Dice rolls
go func() {
for i := 0; ; i++ {
c <- rand.Intn(6) + 1
time.Sleep(time.Duration(500 * time.Millisecond))
}
}()
return c
}
打印输出
...
Tally of B is: 17656
Tally of A is: 17438
Tally of A is: 17440
Tally of B is: 17659
Tally of B is: 17660
Tally of A is: 17445
实现了加密安全的随机数生成器。
package main
import (
"crypto/rand"
"fmt"
"math/big"
"time"
)
func main() {
// launches 2 generatores and the fanIn collector function
c := fanIn(genrt(), genrt())
for i := 0; i < 10000; i++ {
fmt.Println(<-c)
}
}
func fanIn(a <-chan int, b <-chan int) <-chan string {
c := make(chan string)
// launch collector from a to channel
go func() {
var count int
for {
count += <-a
c <- fmt.Sprintf("Tally of A is: %d", count)
}
}()
// launch collector from b to channel
go func() {
var count int
for {
count += <-b
c <- fmt.Sprintf("Tally of B is: %d", count)
}
}()
return c
}
func genrt() <-chan int {
c := make(chan int)
// launch generator of Dice rolls
go func() {
for i := 0; ; i++ {
dice, err := rand.Int(rand.Reader, big.NewInt(6))
if err != nil {
fmt.Println(err)
}
c <- int(dice.Int64()) + 1
time.Sleep(time.Duration(1 * time.Millisecond))
}
}()
return c
}
打印输出
...
Tally of B is: 17496
Tally of A is: 17570
Tally of A is: 17574
Tally of B is: 17500
Tally of B is: 17505
Tally of A is: 17576
查看原文1. 前言 原文地址 之前发现了golang标准库中又两个rand软件包,开始非常想知道他们之间的差异. math/rand软件包可以用于简单的游戏,但不能用于真正的随机性。 math/rand: 伪随机数生成器 crypto/rand: 加密安全的随机数生成器 Rob Pike的代码 {代码...} 2. Math/ran...
查看全部 个人动态 →
golang 的图像验证码 为RESTful API 而设计
注册于 2016-08-12
个人主页被 1.1k 人浏览
推荐关注