Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
E
enoch
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
DevOps
enoch
Commits
0839b0e8
Commit
0839b0e8
authored
Dec 11, 2019
by
jingbo.wang
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
页面显示 & 发送邮件 的api 完成
parent
6f581e80
Changes
7
Hide whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
325 additions
and
25 deletions
+325
-25
go.mod
go.mod
+1
-0
main.go
main.go
+12
-19
api_server.go
pkg/api-server/api_server.go
+121
-0
api_server_test.go
pkg/api-server/api_server_test.go
+53
-0
api.go
pkg/report-form/api.go
+100
-0
report_form.go
pkg/report-form/report_form.go
+33
-6
service.go
pkg/report-form/service.go
+5
-0
No files found.
go.mod
View file @
0839b0e8
...
@@ -4,6 +4,7 @@ go 1.12
...
@@ -4,6 +4,7 @@ go 1.12
require (
require (
github.com/Shopify/sarama v1.23.1
github.com/Shopify/sarama v1.23.1
github.com/buaazp/fasthttprouter v0.1.1
github.com/influxdata/influxdb v1.7.9
github.com/influxdata/influxdb v1.7.9
github.com/mkevac/debugcharts v0.0.0-20180124214838-d3203a8fa926
github.com/mkevac/debugcharts v0.0.0-20180124214838-d3203a8fa926
github.com/shirou/w32 v0.0.0-20160930032740-bb4de0191aa4 // indirect
github.com/shirou/w32 v0.0.0-20160930032740-bb4de0191aa4 // indirect
...
...
main.go
View file @
0839b0e8
...
@@ -2,18 +2,19 @@ package main
...
@@ -2,18 +2,19 @@ package main
import
(
import
(
"fmt"
"fmt"
api_server
"git.quantgroup.cn/DevOps/enoch/pkg/api-server"
"git.quantgroup.cn/DevOps/enoch/pkg/dao"
"git.quantgroup.cn/DevOps/enoch/pkg/dao"
"git.quantgroup.cn/DevOps/enoch/pkg/global"
"git.quantgroup.cn/DevOps/enoch/pkg/global"
"git.quantgroup.cn/DevOps/enoch/pkg/glog"
"git.quantgroup.cn/DevOps/enoch/pkg/glog"
"git.quantgroup.cn/DevOps/enoch/pkg/points"
"git.quantgroup.cn/DevOps/enoch/pkg/points"
report_form
"git.quantgroup.cn/DevOps/enoch/pkg/report-form"
"github.com/Shopify/sarama"
"github.com/Shopify/sarama"
_
"github.com/mkevac/debugcharts"
_
"github.com/mkevac/debugcharts"
"github.com/valyala/fasthttp"
"net/http"
"net/http"
_
"net/http/pprof"
_
"net/http/pprof"
"os"
"os"
"os/signal"
"os/signal"
"runtime/debug"
"strconv"
"strings"
"strings"
"syscall"
"syscall"
"time"
"time"
...
@@ -111,32 +112,24 @@ func main() {
...
@@ -111,32 +112,24 @@ func main() {
dao
.
DbInit
()
dao
.
DbInit
()
//健康状态报表
//健康状态报表
//
report_form.RegularReport(global.ReportFormDir)
report_form
.
RegularReport
(
global
.
ReportFormDir
)
//TODO 告警策略
//TODO 告警策略
}
}
//对外api
//对外api
runApiServer
()
api_server
.
ListenAndServe
()
//处理消息(阻塞)
//处理消息(阻塞)
handlerKafkaMsg
()
handlerKafkaMsg
()
}
}
func
runApiServer
()
{
func
init
()
{
http
.
HandleFunc
(
"/tech/health/check"
,
func
(
writer
http
.
ResponseWriter
,
request
*
http
.
Request
)
{
api_server
.
HandlerFunc
(
api_server
.
GET
,
"/tech/health/check"
,
healthCheck
)
writer
.
WriteHeader
(
http
.
StatusOK
)
api_server
.
HandlerFunc
(
api_server
.
HEAD
,
"/tech/health/check"
,
healthCheck
)
})
}
go
func
()
{
func
healthCheck
(
ctx
*
fasthttp
.
RequestCtx
)
{
defer
func
()
{
ctx
.
Response
.
SetStatusCode
(
fasthttp
.
StatusOK
)
if
err
:=
recover
();
err
!=
nil
{
ctx
.
Response
.
SetBodyString
(
"ok"
)
glog
.
Error
(
err
,
debug
.
Stack
())
}
}()
err
:=
http
.
ListenAndServe
(
":"
+
strconv
.
Itoa
(
global
.
HttpPort
),
nil
)
if
err
!=
nil
{
glog
.
Error
(
err
)
}
}()
}
}
pkg/api-server/api_server.go
0 → 100644
View file @
0839b0e8
package
api_server
import
(
"fmt"
"git.quantgroup.cn/DevOps/enoch/pkg/global"
"git.quantgroup.cn/DevOps/enoch/pkg/glog"
"github.com/buaazp/fasthttprouter"
"github.com/valyala/fasthttp"
"github.com/vrg0/go-common/logger"
"github.com/vrg0/go-common/util"
"runtime"
"strconv"
"strings"
"sync"
"time"
)
var
(
router
=
fasthttprouter
.
New
()
once
=
new
(
sync
.
Once
)
)
const
(
GET
=
"GET"
PUT
=
"PUT"
DELETE
=
"DELETE"
POST
=
"POST"
PATCH
=
"PATCH"
HEAD
=
"HEAD"
OPTIONS
=
"OPTIONS"
)
//跨域
func
wrap
(
handler
fasthttp
.
RequestHandler
)
fasthttp
.
RequestHandler
{
return
func
(
ctx
*
fasthttp
.
RequestCtx
)
{
handler
(
ctx
)
ctx
.
Response
.
Header
.
Add
(
"Access-Control-Allow-Origin"
,
"*"
)
}
}
//注册函数
//HandlerFunc只能在init()中执行
func
HandlerFunc
(
method
string
,
path
string
,
handle
fasthttp
.
RequestHandler
)
{
if
pc
,
_
,
_
,
ok
:=
runtime
.
Caller
(
1
);
ok
&&
strings
.
Contains
(
runtime
.
FuncForPC
(
pc
)
.
Name
(),
".init"
)
{
router
.
Handle
(
method
,
path
,
handle
)
}
else
{
glog
.
Error
(
"HandlerFunc must be execute in init()"
)
}
}
//程序对外API的http-server
//启动服务
func
ListenAndServe
()
{
once
.
Do
(
listenAndServe
)
}
func
listenAndServe
()
{
//handlerFunc 发生 panic 后返回的内容
router
.
PanicHandler
=
func
(
ctx
*
fasthttp
.
RequestCtx
,
i
interface
{})
{
rtn
:=
"panic: "
+
ctx
.
String
()
+
" "
switch
x
:=
i
.
(
type
)
{
case
error
:
rtn
+=
x
.
Error
()
case
string
:
rtn
+=
x
default
:
rtn
+=
"未识别的panic类型"
}
rtn
+=
"
\n
"
rtn
+=
ctx
.
Request
.
String
()
glog
.
Error
(
rtn
)
ctx
.
Response
.
SetStatusCode
(
500
)
ctx
.
Response
.
SetBodyString
(
rtn
)
}
//启动http server
go
func
()
{
//server panic后自动重启
defer
func
()
{
if
err
:=
recover
();
err
!=
nil
{
errStr
:=
fmt
.
Sprint
(
"api fasthttp panic:"
,
err
)
glog
.
Error
(
errStr
)
time
.
Sleep
(
time
.
Second
*
1
)
listenAndServe
()
}
}()
//创建http-server对象
l
:=
global
.
Logger
.
GetStandardLogger
()
l
.
SetPrefix
(
"_API_SERVER_ "
)
hook
:=
logger
.
NewHookWriter
(
l
.
Writer
())
hook
.
AddHookFunc
(
func
(
data
[]
byte
)
bool
{
body
:=
util
.
BytesString
(
data
)
if
strings
.
Contains
(
body
,
"error"
)
{
}
return
true
})
l
.
SetOutput
(
hook
)
server
:=
fasthttp
.
Server
{
Logger
:
l
,
Handler
:
wrap
(
router
.
Handler
),
}
//启动http-server
firstRunFlag
:=
true
for
{
if
firstRunFlag
{
firstRunFlag
=
false
}
else
{
time
.
Sleep
(
time
.
Second
*
1
)
//二次重启延时1秒
}
if
err
:=
server
.
ListenAndServe
(
"0.0.0.0:"
+
strconv
.
Itoa
(
global
.
HttpPort
));
err
!=
nil
{
glog
.
Error
(
"api fasthttp err"
,
err
)
}
}
}()
//等待http-server启动成功
time
.
Sleep
(
time
.
Millisecond
*
100
)
}
pkg/api-server/api_server_test.go
0 → 100644
View file @
0839b0e8
package
api_server
import
(
"github.com/valyala/fasthttp"
"strings"
"testing"
)
func
init
()
{
//正确执行的测试场景
HandlerFunc
(
GET
,
"/hello"
,
func
(
ctx
*
fasthttp
.
RequestCtx
)
{
ctx
.
Response
.
SetBodyString
(
"hello!"
)
})
//panic测试场景
HandlerFunc
(
GET
,
"/panic"
,
func
(
ctx
*
fasthttp
.
RequestCtx
)
{
panic
(
"panic_test"
)
})
}
//测试panic回调函数是否好用
func
TestHandlerFuncPanic
(
t
*
testing
.
T
)
{
ListenAndServe
()
if
_
,
body
,
err
:=
fasthttp
.
Get
(
nil
,
"http://127.0.0.1:5555/panic"
);
err
!=
nil
{
t
.
Error
(
err
)
}
else
if
!
strings
.
Contains
(
string
(
body
),
"panic_test"
)
{
t
.
Error
(
"recover panic fatal"
)
}
}
//测试http-server是否启动
func
TestListenAndServe
(
t
*
testing
.
T
)
{
ListenAndServe
()
if
_
,
_
,
err
:=
fasthttp
.
Get
(
nil
,
"http://127.0.0.1:5555/hello"
);
err
!=
nil
{
t
.
Error
(
err
)
}
}
//不在init()中执行会报panic
func
TestHandlerFunc
(
t
*
testing
.
T
)
{
defer
func
()
{
if
err
:=
recover
();
err
!=
nil
{
if
errStr
,
ok
:=
err
.
(
string
);
!
ok
||
errStr
!=
"HandlerFunc must be execute in init()"
{
t
.
Error
(
"HandlerFunc Err"
)
}
}
}()
HandlerFunc
(
GET
,
"/test"
,
func
(
ctx
*
fasthttp
.
RequestCtx
)
{
ctx
.
Response
.
SetBodyString
(
"test!"
)
})
}
pkg/report-form/api.go
0 → 100644
View file @
0839b0e8
package
report_form
import
(
"encoding/json"
"fmt"
"git.quantgroup.cn/DevOps/enoch/pkg/api-server"
"git.quantgroup.cn/DevOps/enoch/pkg/email"
"git.quantgroup.cn/DevOps/enoch/pkg/global"
"github.com/valyala/fasthttp"
"github.com/vrg0/go-common/util"
"io/ioutil"
)
func
show
(
ctx
*
fasthttp
.
RequestCtx
)
{
long
:=
ctx
.
UserValue
(
"long"
)
.
(
string
)
y
:=
ctx
.
UserValue
(
"y"
)
.
(
string
)
m
:=
ctx
.
UserValue
(
"m"
)
.
(
string
)
d
:=
ctx
.
UserValue
(
"d"
)
.
(
string
)
name
:=
ctx
.
UserValue
(
"name"
)
.
(
string
)
if
long
!=
"day"
&&
long
!=
"week"
{
ctx
.
Response
.
SetStatusCode
(
fasthttp
.
StatusNotFound
)
ctx
.
Response
.
SetBodyString
(
"page not found"
)
return
}
if
len
(
m
)
==
1
{
m
=
"0"
+
m
}
if
len
(
d
)
==
1
{
d
=
"0"
+
d
}
date
:=
fmt
.
Sprintf
(
"%s-%s-%s"
,
y
,
m
,
d
)
filePath
:=
global
.
ReportFormDir
+
"/"
+
date
+
"/"
+
long
+
"/"
+
name
+
".html"
if
!
util
.
Exists
(
filePath
)
{
ctx
.
Response
.
SetStatusCode
(
fasthttp
.
StatusBadRequest
)
ctx
.
Response
.
SetBodyString
(
"超出查询范围"
)
return
}
body
,
err
:=
ioutil
.
ReadFile
(
filePath
)
if
err
!=
nil
{
ctx
.
Response
.
SetStatusCode
(
fasthttp
.
StatusBadRequest
)
ctx
.
Response
.
SetBodyString
(
"读取文件失败"
)
}
ctx
.
Response
.
Header
.
SetContentType
(
"text/html"
)
ctx
.
Response
.
SetStatusCode
(
fasthttp
.
StatusOK
)
ctx
.
Response
.
SetBody
(
body
)
}
func
sendEmail
(
ctx
*
fasthttp
.
RequestCtx
)
{
long
:=
ctx
.
UserValue
(
"long"
)
.
(
string
)
y
:=
ctx
.
UserValue
(
"y"
)
.
(
string
)
m
:=
ctx
.
UserValue
(
"m"
)
.
(
string
)
d
:=
ctx
.
UserValue
(
"d"
)
.
(
string
)
name
:=
ctx
.
UserValue
(
"name"
)
.
(
string
)
if
long
!=
"day"
&&
long
!=
"week"
{
ctx
.
Response
.
SetStatusCode
(
fasthttp
.
StatusNotFound
)
ctx
.
Response
.
SetBodyString
(
"page not found"
)
return
}
if
len
(
m
)
==
1
{
m
=
"0"
+
m
}
if
len
(
d
)
==
1
{
d
=
"0"
+
d
}
date
:=
fmt
.
Sprintf
(
"%s-%s-%s"
,
y
,
m
,
d
)
filePath
:=
global
.
ReportFormDir
+
"/"
+
date
+
"/"
+
long
+
"/"
+
name
+
".html"
if
!
util
.
Exists
(
filePath
)
{
ctx
.
Response
.
SetStatusCode
(
fasthttp
.
StatusBadRequest
)
ctx
.
Response
.
SetBodyString
(
"超出查询范围"
)
return
}
body
,
err
:=
ioutil
.
ReadFile
(
filePath
)
if
err
!=
nil
{
ctx
.
Response
.
SetStatusCode
(
fasthttp
.
StatusBadRequest
)
ctx
.
Response
.
SetBodyString
(
"读取文件失败"
)
return
}
emailList
:=
make
([]
string
,
0
)
if
err
:=
json
.
Unmarshal
(
ctx
.
Request
.
Body
(),
&
emailList
);
err
!=
nil
{
ctx
.
Response
.
SetStatusCode
(
fasthttp
.
StatusBadRequest
)
ctx
.
Response
.
SetBodyString
(
"can not unmarshal body"
)
return
}
email
.
SendEmail
(
fmt
.
Sprintf
(
"服务健康状态表:%s_%s_%s"
,
name
,
date
,
long
),
util
.
BytesString
(
body
),
emailList
...
)
}
func
init
()
{
//显示报表
api_server
.
HandlerFunc
(
api_server
.
GET
,
"/show/:long/:y/:m/:d/:name"
,
show
)
//发送邮件:周
api_server
.
HandlerFunc
(
api_server
.
POST
,
"/send-email/:long/:y/:m/:d/:name"
,
sendEmail
)
}
pkg/report-form/report_form.go
View file @
0839b0e8
...
@@ -36,17 +36,42 @@ func hrn(n int) string {
...
@@ -36,17 +36,42 @@ func hrn(n int) string {
return
fmt
.
Sprintf
(
"%.3f%s"
,
r
,
pre
)
return
fmt
.
Sprintf
(
"%.3f%s"
,
r
,
pre
)
}
}
//TODO 分表
func
(
sm
*
ServiceMap
)
ServiceReportForm
()
map
[
string
]
string
{
rtn
:=
make
(
map
[
string
]
string
)
//
return
rtn
}
//获取指定path的访问量
func
(
sm
*
ServiceMap
)
GetPathCount
(
serviceName
string
,
path
string
)
int
{
s
,
ok
:=
sm
.
serviceMap
[
serviceName
]
if
!
ok
{
return
0
}
pm
:=
s
.
GetPathMap
()
p
,
ok
:=
pm
[
path
]
if
!
ok
{
return
0
}
return
p
.
GetCount
()
}
//总表
//总表
func
(
sm
*
ServiceMap
)
ServiceMapReportForm
()
string
{
func
(
sm
*
ServiceMap
)
ServiceMapReportForm
()
string
{
rtn
:=
new
(
strings
.
Builder
)
rtn
:=
new
(
strings
.
Builder
)
var
t
*
Table
=
nil
var
t
*
Table
=
nil
//表头
//表头
rtn
.
WriteString
(
"<div><pre>
\n
"
)
rtn
.
WriteString
(
"<
html><head><meta http-equiv=
\"
Content-Type
\"
content=
\"
text/html; charset=utf-8
\"
/></head><body><
div><pre>
\n
"
)
rtn
.
WriteString
(
" 服务健康状态总表
\n
"
)
rtn
.
WriteString
(
" 服务健康状态总表
\n
"
)
rtn
.
WriteString
(
fmt
.
Sprintf
(
"时间:%s ~ %s
\n
"
,
rtn
.
WriteString
(
fmt
.
Sprintf
(
"时间:%s ~ %s
\n
"
,
sm
.
startTime
.
In
(
cstZone
)
.
Format
(
time
.
RFC3339
),
sm
.
startTime
.
In
(
cstZone
)
.
Format
(
time
Format
),
sm
.
endTime
.
In
(
cstZone
)
.
Format
(
time
.
RFC3339
)),
sm
.
endTime
.
In
(
cstZone
)
.
Format
(
time
Format
)),
)
)
rtn
.
WriteString
(
fmt
.
Sprintf
(
"总访问量:%s 总响应时间:%s 平均响应时间:%s QPS:%.2f
\n
"
,
rtn
.
WriteString
(
fmt
.
Sprintf
(
"总访问量:%s 总响应时间:%s 平均响应时间:%s QPS:%.2f
\n
"
,
hrn
(
sm
.
GetCount
()),
hrn
(
sm
.
GetCount
()),
...
@@ -139,12 +164,13 @@ func (sm *ServiceMap) ServiceMapReportForm() string {
...
@@ -139,12 +164,13 @@ func (sm *ServiceMap) ServiceMapReportForm() string {
//响应时间最高的请求排行
//响应时间最高的请求排行
getMaxDurationTracePointList
:=
sm
.
GetMaxDurationTracePointList
()
getMaxDurationTracePointList
:=
sm
.
GetMaxDurationTracePointList
()
if
len
(
getMaxDurationTracePointList
)
!=
0
{
if
len
(
getMaxDurationTracePointList
)
!=
0
{
t
=
NewTable
(
"响应时间最高的请求排行"
,
"排名"
,
"响应时间"
,
"服务名称"
,
"接口"
,
"时间戳"
,
"trace_id"
)
t
=
NewTable
(
"响应时间最高的请求排行"
,
"排名"
,
"响应时间"
,
"服务名称"
,
"接口"
,
"时间戳"
,
"trace_id"
,
"访问量"
)
for
i
,
tp
:=
range
getMaxDurationTracePointList
{
for
i
,
tp
:=
range
getMaxDurationTracePointList
{
color
:=
colorBlack
color
:=
colorBlack
if
tp
.
Duration
>
maxDuration
{
if
tp
.
Duration
>
maxDuration
{
color
=
colorRed
color
=
colorRed
}
}
//访问量
_
=
t
.
AddRecord
(
_
=
t
.
AddRecord
(
color
,
color
,
fmt
.
Sprintf
(
"No.%d"
,
i
+
1
),
fmt
.
Sprintf
(
"No.%d"
,
i
+
1
),
...
@@ -152,7 +178,8 @@ func (sm *ServiceMap) ServiceMapReportForm() string {
...
@@ -152,7 +178,8 @@ func (sm *ServiceMap) ServiceMapReportForm() string {
tp
.
ServiceName
,
tp
.
ServiceName
,
tp
.
Path
,
tp
.
Path
,
tp
.
Timestamp
.
In
(
cstZone
)
.
Format
(
timeFormat
),
tp
.
Timestamp
.
In
(
cstZone
)
.
Format
(
timeFormat
),
tp
.
TraceId
,
fmt
.
Sprintf
(
`<a href="http://zipkin-3c.xyqb.com/zipkin/traces/%s" target="_blank" rel="noopener noreferrer">%s</a>`
,
tp
.
TraceId
,
tp
.
TraceId
),
hrn
(
sm
.
GetPathCount
(
tp
.
ServiceName
,
tp
.
Path
)),
)
)
}
}
if
!
t
.
IsEmpty
()
{
if
!
t
.
IsEmpty
()
{
...
@@ -299,7 +326,7 @@ func (sm *ServiceMap) ServiceMapReportForm() string {
...
@@ -299,7 +326,7 @@ func (sm *ServiceMap) ServiceMapReportForm() string {
}
}
}
}
rtn
.
WriteString
(
"</pre></div>
\n
"
)
rtn
.
WriteString
(
"</pre></div>
</body></html>
\n
"
)
return
rtn
.
String
()
return
rtn
.
String
()
}
}
...
...
pkg/report-form/service.go
View file @
0839b0e8
...
@@ -96,6 +96,11 @@ func (s *Service) Name() string {
...
@@ -96,6 +96,11 @@ func (s *Service) Name() string {
return
s
.
name
return
s
.
name
}
}
//获取Path Map
func
(
s
*
Service
)
GetPathMap
()
map
[
string
]
*
Path
{
return
s
.
pathMap
}
//获取节点列表
//获取节点列表
func
(
s
*
Service
)
getNodeList
()
[]
string
{
func
(
s
*
Service
)
getNodeList
()
[]
string
{
const
sqlGetNodeList
=
`SHOW TAG VALUES FROM machine_info WITH key = "host" WHERE sys_name = '%s';`
const
sqlGetNodeList
=
`SHOW TAG VALUES FROM machine_info WITH key = "host" WHERE sys_name = '%s';`
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment