monitor.go 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431
  1. package service
  2. import (
  3. "context"
  4. "regexp"
  5. "strconv"
  6. "strings"
  7. "go-common/app/interface/openplatform/monitor-end/model"
  8. "go-common/app/interface/openplatform/monitor-end/model/monitor"
  9. "go-common/app/interface/openplatform/monitor-end/model/prom"
  10. "go-common/library/log"
  11. "github.com/json-iterator/go"
  12. )
  13. const _regex = `.*\d{2,}`
  14. var json = jsoniter.ConfigCompatibleWithStandardLibrary
  15. const (
  16. _typeAPP = "app"
  17. _typeWeb = "web/h5"
  18. _typeAPPH = "app_h"
  19. _eventPage = "page"
  20. _eventAPI = "api"
  21. _eventResource = "resource"
  22. _levelInfo = "info"
  23. _levelWarning = "warning"
  24. _levelError = "error"
  25. _logTypeOne = "1"
  26. _logTypeTwo = "2"
  27. )
  28. // Report .
  29. func (s *Service) Report(c context.Context, params *model.LogParams, mid int64, ip string, buvid string, userAgent string) (err error) {
  30. var l *monitor.Log
  31. log.Info("get log report(%+v)", params)
  32. if params.IsAPP == 1 {
  33. _, err = s.nativeLog(c, params.Log)
  34. } else {
  35. l, err = s.frontendLog(c, params.Source, params.Log, mid, ip, buvid, userAgent)
  36. go s.promsFE(context.TODO(), l)
  37. }
  38. return
  39. }
  40. func induceSubEvent(s string) string {
  41. if strings.Contains(s, "?") {
  42. s = s[:strings.Index(s, "?")]
  43. }
  44. if strings.Contains(s, "://") {
  45. s = s[(strings.Index(s, "://") + 3):]
  46. }
  47. if len(s) > 512 {
  48. s = s[:512]
  49. }
  50. var (
  51. ok bool
  52. err error
  53. )
  54. for {
  55. if ok, err = regexp.Match(_regex, []byte(s)); err != nil {
  56. log.Error("s.Report.regexp error(%+v), data(%s)", err, s)
  57. return s
  58. }
  59. if !ok {
  60. break
  61. }
  62. if !strings.Contains(s, "/") {
  63. return s
  64. }
  65. s = s[:strings.LastIndex(s, "/")]
  66. }
  67. return s
  68. }
  69. func (s *Service) promsFE(c context.Context, l *monitor.Log) {
  70. if !s.c.Prom.Promed || l == nil {
  71. return
  72. }
  73. var (
  74. ok bool
  75. err error
  76. )
  77. l.SubEvent = induceSubEvent(l.SubEvent)
  78. if l.Event == _eventResource {
  79. regex := `.*i\d{1}.hdslb.com`
  80. if ok, err = regexp.Match(regex, []byte(l.SubEvent)); err != nil {
  81. log.Error("s.Report.regexp error(%+v), data(%s)", err, l.SubEvent)
  82. return
  83. }
  84. if ok {
  85. l.SubEvent = l.SubEvent[:strings.Index(l.SubEvent, "hdslb.com")+9]
  86. }
  87. prom.AddCode(l.Type, l.SubProduct, l.SubEvent, l.Event, l.Ver, l.BusinessCode)
  88. return
  89. }
  90. prom.AddHTTPCode(l.Type, l.SubProduct, l.SubEvent, l.Event, l.Ver, l.HTTPCode)
  91. prom.AddCode(l.Type, l.SubProduct, l.SubEvent, l.Event, l.Ver, l.BusinessCode)
  92. if l.Details == nil {
  93. var cost int64
  94. if l.Duration == "" {
  95. return
  96. }
  97. if cost, err = strconv.ParseInt(l.Duration, 10, 64); err != nil {
  98. log.Warn("s.Info.ParseInt can not convert duration(%s) to int64", l.Duration)
  99. return
  100. }
  101. prom.AddCommonLog(l.Type, l.SubProduct, l.SubEvent, l.Event, l.Ver, cost)
  102. } else {
  103. prom.AddDetailedLog(l.Type, l.SubProduct, l.SubEvent, l.Event, l.Ver, l.Details)
  104. }
  105. }
  106. func (s *Service) nativeLog(c context.Context, data string) (l *monitor.Log, err error) {
  107. l = &monitor.Log{}
  108. if err = json.Unmarshal([]byte(data), l); err != nil {
  109. log.Error("s.nativeLog.unmarshal error(%+v), data(%s)", err, data)
  110. return
  111. }
  112. l.Type = _typeAPPH
  113. s.handleLog(c, l)
  114. return
  115. }
  116. // HandleMsg .
  117. func (s *Service) HandleMsg(msg []byte) {
  118. l := monitor.LogFromBytes(msg)
  119. l.Type = _typeAPP
  120. s.handleLog(context.TODO(), l)
  121. }
  122. func (s *Service) handleLog(c context.Context, l *monitor.Log) {
  123. var (
  124. appID string
  125. kv []log.D
  126. err error
  127. logtype int
  128. isInt bool
  129. cost int64
  130. ok bool
  131. app = "android"
  132. )
  133. l.TraceidSvr = l.Traceid
  134. l.Traceid = ""
  135. l.CalCode()
  136. if appID, _, kv, err = l.LogData(); err != nil {
  137. log.Error("s.nativeLog.LogData error(%+v), data(%+v)", err, l)
  138. return
  139. }
  140. if l.Result == "1" || l.Result == "" {
  141. s.mh.Info(c, appID, kv...)
  142. } else {
  143. s.mh.Error(c, appID, kv...)
  144. }
  145. if l.SubProduct == "" {
  146. l.SubProduct = l.Product
  147. }
  148. if strings.Contains(l.RequestURI, "ios") {
  149. app = "ios"
  150. isInt = true
  151. }
  152. if logtype, err = bStrToInt(l.LogType, isInt); err != nil {
  153. return
  154. }
  155. if s.c.Prom.IgnoreNA && !s.checkProduct(l) {
  156. return
  157. }
  158. // 丢弃老版本的network日志
  159. if l.Event == "network" && l.Codes == "" {
  160. return
  161. }
  162. l.SubEvent = induceSubEvent(l.SubEvent)
  163. regex := `.*i\d{1}.hdslb.com`
  164. if ok, err = regexp.Match(regex, []byte(l.SubEvent)); err != nil {
  165. log.Error("s.Report.regexp error(%+v), data(%s)", err, l.SubEvent)
  166. return
  167. }
  168. if ok {
  169. l.SubEvent = l.SubEvent[:strings.Index(l.SubEvent, "hdslb.com")+9]
  170. }
  171. if (logtype & 1) == 1 {
  172. // 性能日志
  173. if cost, err = strconv.ParseInt(l.Duration, 10, 64); err != nil {
  174. log.Warn("s.handleLog.ParseInt can not convert duration(%s) to int64", l.Duration)
  175. return
  176. }
  177. prom.AddCommonLog(app, l.SubProduct, l.SubEvent, l.Event, l.Ver, cost)
  178. }
  179. if (logtype >> 2 & 1) == 1 {
  180. // 成功/失败日志
  181. if l.Event == "network" {
  182. // 网络类型 上报业务码和http状态
  183. prom.AddHTTPCode(app, l.SubProduct, l.SubEvent, l.Event, l.Ver, l.HTTPCode)
  184. prom.AddCode(app, l.SubProduct, l.SubEvent, l.Event, l.Ver, l.BusinessCode)
  185. } else {
  186. // 其他类型 只上报失败成功 result=1 表示成功
  187. res := "999"
  188. if l.Result == "1" {
  189. res = "0"
  190. }
  191. prom.AddCode(app, l.SubProduct, l.SubEvent, l.Event, l.Ver, res)
  192. }
  193. }
  194. }
  195. func (s *Service) frontendLog(c context.Context, source string, data string, mid int64, ip string, buvid string, userAgent string) (l *monitor.Log, err error) {
  196. var (
  197. ms []interface{}
  198. kv []log.D
  199. logtype, loglevel string
  200. url, query string
  201. )
  202. if err = json.Unmarshal([]byte(data), &ms); err != nil {
  203. log.Error("s.frontendLog.unmarshal error(%+v), data(%s)", err, data)
  204. return
  205. }
  206. for _, m := range ms {
  207. switch m := m.(type) {
  208. case map[string]interface{}:
  209. logtype = stringValueByKey(m, "1", "logtype")
  210. loglevel = stringValueByKey(m, "info", "level")
  211. tmp := stringValueByKey(m, "", "url")
  212. if strings.Contains(tmp, "?") {
  213. url = strings.Split(tmp, "?")[0]
  214. query = strings.Split(tmp, "?")[1]
  215. } else {
  216. url = tmp
  217. }
  218. switch logtype {
  219. case _logTypeOne:
  220. l = &monitor.Log{
  221. LogType: _logTypeOne,
  222. Type: _typeWeb,
  223. Product: source,
  224. IP: ip,
  225. Buvid: buvid,
  226. UserAgent: userAgent,
  227. Event: _eventAPI,
  228. Mid: strconv.FormatInt(mid, 10),
  229. SubEvent: url,
  230. Query: query,
  231. Duration: stringValueByKey(m, "", "cost"),
  232. TraceidSvr: stringValueByKey(m, "", "traceid_svr"),
  233. TraceidEnd: stringValueByKey(m, "", "traceid_end"),
  234. HTTPCode: stringValueByKey(m, "200", "status"),
  235. BusinessCode: stringValueByKey(m, "0", "errno", "code"),
  236. SubProduct: stringValueByKey(m, source, "sub_product"),
  237. Result: "0",
  238. }
  239. srcURL := stringValueByKey(m, "", "srcUrl")
  240. if srcURL != "" {
  241. l.Event = _eventResource
  242. l.SubEvent = srcURL
  243. l.BusinessCode = "-999"
  244. }
  245. if loglevel == _levelInfo {
  246. l.Result = "1"
  247. }
  248. if _, _, kv, err = l.LogData(); err != nil {
  249. return
  250. }
  251. kv = append(kv, extKV(m)...)
  252. case _logTypeTwo:
  253. var msg []byte
  254. l = &monitor.Log{
  255. LogType: _logTypeTwo,
  256. Type: _typeWeb,
  257. Product: source,
  258. Event: _eventPage,
  259. IP: ip,
  260. Buvid: buvid,
  261. UserAgent: userAgent,
  262. Mid: strconv.FormatInt(mid, 10),
  263. SubEvent: url,
  264. Query: query,
  265. HTTPCode: "200",
  266. Details: details(m),
  267. Result: "1",
  268. BusinessCode: "0",
  269. SubProduct: stringValueByKey(m, source, "sub_product"),
  270. }
  271. if msg, err = json.Marshal(m); err != nil {
  272. log.Error("s.frontendLog.Marshal error(%v), data(%v)", err, m)
  273. continue
  274. }
  275. l.Message = string(msg)
  276. if _, _, kv, err = l.LogData(); err != nil {
  277. return
  278. }
  279. default:
  280. log.Error("s.frontendLog error logype(%v)", logtype)
  281. return
  282. }
  283. switch loglevel {
  284. case _levelInfo:
  285. s.mh.Info(c, source, kv...)
  286. case _levelWarning:
  287. s.mh.Warn(c, source, kv...)
  288. case _levelError:
  289. s.collectFE(c, l)
  290. s.mh.Error(c, source, kv...)
  291. default:
  292. s.mh.Info(c, source, kv...)
  293. }
  294. default:
  295. log.Error("s.frontendLog log data is not json type: " + data)
  296. }
  297. }
  298. return
  299. }
  300. func (s *Service) collectFE(c context.Context, l *monitor.Log) {
  301. if s.c.CollectFE {
  302. regex := `.*i\d{1}.hdslb.com`
  303. if ok, err := regexp.Match(regex, []byte(l.SubEvent)); err != nil {
  304. log.Error("s.Report.regexp error(%+v), data(%s)", err, l.SubEvent)
  305. return
  306. } else if ok {
  307. l.SubEvent = l.SubEvent[:strings.Index(l.SubEvent, "hdslb.com")+9]
  308. }
  309. go s.Collect(context.TODO(), l)
  310. }
  311. }
  312. func stringValueByKey(m map[string]interface{}, defValue string, keys ...string) (r string) {
  313. r = defValue
  314. if m == nil {
  315. return
  316. }
  317. var (
  318. res interface{}
  319. ok bool
  320. )
  321. for _, key := range keys {
  322. if res, ok = m[key]; ok {
  323. break
  324. }
  325. return
  326. }
  327. if res == nil {
  328. return
  329. }
  330. switch d := res.(type) {
  331. case int:
  332. r = strconv.Itoa(d)
  333. case float64:
  334. r = strconv.FormatFloat(d, 'f', -1, 64)
  335. case int64:
  336. r = strconv.FormatInt(d, 10)
  337. case string:
  338. r = d
  339. default:
  340. log.Warn("s.stringValueByKey unexcept type of value(%v)", d)
  341. }
  342. return
  343. }
  344. func extKV(m map[string]interface{}) (kv []log.D) {
  345. if m == nil {
  346. return
  347. }
  348. var keys = []string{"level", "logtype", "url", "cost", "traceid_svr", "traceid_end", "status", "code", "errno", "sub_product"}
  349. for _, key := range keys {
  350. delete(m, key)
  351. }
  352. for k, v := range m {
  353. kv = append(kv, log.KV(k, v))
  354. }
  355. return
  356. }
  357. func details(m map[string]interface{}) (res map[string]int64) {
  358. res = make(map[string]int64)
  359. if m == nil {
  360. return
  361. }
  362. delete(m, "level")
  363. delete(m, "logtype")
  364. delete(m, "url")
  365. for k, v := range m {
  366. var d int64
  367. if v == nil {
  368. res[k] = 0
  369. continue
  370. }
  371. switch v := v.(type) {
  372. case int64:
  373. d = v
  374. case float64:
  375. d = int64(v)
  376. case int:
  377. d = int64(v)
  378. case int32:
  379. d = int64(v)
  380. case string:
  381. d, _ = strconv.ParseInt(v, 10, 64)
  382. default:
  383. log.Warn("s.details unexcept type of value(%v)", v)
  384. }
  385. res[k] = d
  386. }
  387. return
  388. }
  389. func bStrToInt(str string, isInt bool) (r int, err error) {
  390. if isInt {
  391. if r, err = strconv.Atoi(str); err != nil {
  392. log.Warn("s.bStrToInt error(%+v), string(%s)", err, str)
  393. }
  394. return
  395. }
  396. for _, i := range str {
  397. if i == '1' {
  398. r = r*2 + 1
  399. } else {
  400. r *= 2
  401. }
  402. }
  403. return
  404. }
  405. func (s *Service) checkProduct(l *monitor.Log) bool {
  406. if s.naProducts == nil {
  407. return true
  408. }
  409. if s.naProducts[l.Product] {
  410. return true
  411. }
  412. return false
  413. }