diff --git a/README.md b/README.md index 5860498..08d82d2 100644 --- a/README.md +++ b/README.md @@ -12,4 +12,5 @@ Golang utility packages - [goutils/echomiddleware](/echomiddleware) - [goutils/echotpl](/echotpl) - [goutils/jwtutil](/jwtutil) -- [goutils/cronjob](/cronjob) \ No newline at end of file +- [goutils/cronjob](/cronjob) +- [goutils/joblog](/joblog) \ No newline at end of file diff --git a/joblog/README.md b/joblog/README.md new file mode 100644 index 0000000..38cb444 --- /dev/null +++ b/joblog/README.md @@ -0,0 +1,37 @@ +# joblog + +log print for eland job monitor + +## Getting Started + +```golang +jobLog := joblog.New(url,"test", map[string]interface{}{"log": "this is test"}) + +err := jobLog.Info("good") +test.Ok(t, err) + +err = jobLog.Warning(struct{ Name string }{"xiaoxinmiao"}) +test.Ok(t, err) + +err = jobLog.Error(errors.New("this is bug.")) +test.Ok(t, err) +``` +### `joblog.New` + +Create job log + +- `url` - Save data to job monitor via this url,like:https://xxx.com.cn/batchjob-api/v1/jobs +- `serviceName` - The name of the microservice to store the log, usually the project name, for example: ibill-qa +- `firstMessage` - Print the contents of the first log,it can only pass `struct`, `pointer struct` or `maps`. +- `options` - Optional parameters can be modified. + +### `Info Warning Error ` + +Print info/warning/error log + +- `message` - Print the contents of log,It can pass `any type` of parameter. + +## View log + +https://wiki.elandsystems.cn/display/DBA/Batch-job+Monitor + diff --git a/joblog/joblog.go b/joblog/joblog.go new file mode 100644 index 0000000..2b15020 --- /dev/null +++ b/joblog/joblog.go @@ -0,0 +1,134 @@ +package joblog + +import ( + "encoding/json" + "errors" + "fmt" + "net/http" + "reflect" + + "github.com/pangpanglabs/goutils/httpreq" +) + +type JobLog struct { + url string + serviceName string + jobId int64 + Disable bool + Err error +} + +type jobStartDto struct { + Servcie string `json:"service"` + Param interface{} `json:"param"` +} + +type messageLevel struct { + Level string `json:"level"` + Message string `json:"message"` +} + +func New(url, serviceName string, firstMessage interface{}, options ...func(*JobLog)) (jobLog *JobLog) { + jobLog = &JobLog{ + url: url, + serviceName: serviceName, + } + for _, option := range options { + if option == nil { + continue + } + option(jobLog) + } + if jobLog.Disable == true { + return + } + if len(jobLog.serviceName) == 0 { + jobLog.Err = errors.New("serviceName is missing.") + return + } + var result struct { + Result int64 `json:"result"` + } + if ok, kind := validParam(firstMessage); !ok { + jobLog.Err = fmt.Errorf("firstMessage type act:%v,exp:%v.", + kind, "Struct, Map, Ptr") + return + } + _, jobLog.Err = httpreq.New(http.MethodPost, jobLog.url, &jobStartDto{ + Servcie: jobLog.serviceName, + Param: firstMessage, + }).Call(&result) + if jobLog.Err != nil { + return + } + jobLog.jobId = result.Result + return +} + +func (r *JobLog) Info(message interface{}) error { + return r.write(message, "info") +} + +func (r *JobLog) Warning(message interface{}) error { + return r.write(message, "warning") +} +func (r *JobLog) Error(message interface{}) error { + return r.write(message, "error") +} + +func (r *JobLog) write(message interface{}, level string) (err error) { + if r.Err != nil { + err = r.Err + return + } + if r.Disable == true { + return + } + url := fmt.Sprintf("%v/%v/logs", r.url, r.jobId) + _, err = httpreq.New(http.MethodPost, url, &messageLevel{ + Message: toString(message), + Level: level, + }).Call(nil) + return +} + +func (r *JobLog) Finish() (err error) { + if r.Err != nil { + err = r.Err + return + } + if r.Disable == true { + return + } + url := fmt.Sprintf("%v/%v/finish", r.url, r.jobId) + httpreq.New(http.MethodPost, url, nil).Call(nil) + return +} + +func toString(raw interface{}) string { + switch v := raw.(type) { + case int, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64, bool, float32, float64: + return fmt.Sprint(v) + case string: + return string(v) + case error: + return v.Error() + } + val := reflect.ValueOf(raw) + switch val.Kind() { + case reflect.Struct, reflect.Map, reflect.Array, reflect.Slice, reflect.Ptr: + b, _ := json.Marshal(raw) + return string(b) + } + return "" +} +func validParam(param interface{}) (ok bool, kind reflect.Kind) { + val := reflect.ValueOf(param) + kind = val.Kind() + switch kind { + case reflect.Struct, reflect.Map, reflect.Ptr: + ok = true + return + } + return +} diff --git a/joblog/joblog_test.go b/joblog/joblog_test.go new file mode 100644 index 0000000..a2bd6b2 --- /dev/null +++ b/joblog/joblog_test.go @@ -0,0 +1,50 @@ +package joblog_test + +import ( + "errors" + "os" + "testing" + + "github.com/pangpanglabs/goutils/joblog" + "github.com/pangpanglabs/goutils/test" +) + +var url = os.Getenv("JOB_LOG") + +func TestLog(t *testing.T) { + //1.test normal logic + jobLog := joblog.New(url, + "test", map[string]interface{}{"log": "this is test"}) + err := jobLog.Info("good") + test.Ok(t, err) + + err = jobLog.Warning(struct{ Name string }{"xiaoxinmiao"}) + test.Ok(t, err) + + err = jobLog.Error(errors.New("this is bug.")) + test.Ok(t, err) + + err = jobLog.Finish() + test.Ok(t, err) + + //2.test Disable:this content will not be logged + jobLog = joblog.New(url, + "test", map[string]interface{}{"log": "this is test 2"}, func(log *joblog.JobLog) { + log.Disable = true + }) + err = jobLog.Info("good 2") + test.Ok(t, err) + + err = jobLog.Warning(struct{ Name string }{"xiaoxinmiao 2"}) + test.Ok(t, err) + + err = jobLog.Error(errors.New("this is bug. 2")) + test.Ok(t, err) + + //3.test start param + type Dto struct{ Message string } + test.Ok(t, joblog.New(url, "test", Dto{Message: "how are you 1"}).Err) + test.Ok(t, joblog.New(url, "test", &Dto{Message: "how are you 2"}).Err) + test.Ok(t, joblog.New(url, "test", map[string]interface{}{"message": "how are you 3"}).Err) + +}