output.go 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166
  1. package main
  2. import (
  3. "encoding/json"
  4. "fmt"
  5. "os"
  6. "strings"
  7. "time"
  8. "github.com/fluent/fluent-logger-golang/fluent"
  9. )
  10. type Output interface {
  11. Post(time *time.Time, tag string, data map[string]interface{})
  12. Close()
  13. }
  14. type Fluentd struct {
  15. Host string
  16. Port int
  17. Tag string
  18. clog chan map[string]interface{}
  19. fluent *fluent.Fluent
  20. }
  21. func NewOutputFluentd(host string, port int, tag string, bufferSize int) Output {
  22. fluent, err := fluent.New(fluent.Config{FluentHost: host, FluentPort: port})
  23. if err != nil {
  24. panic(err)
  25. }
  26. clog := make(chan map[string]interface{}, bufferSize)
  27. go func() {
  28. for message := range clog {
  29. err := fluent.Post(tag, message)
  30. if err != nil {
  31. fmt.Printf("ERROR %s: %v+\n", err, message)
  32. }
  33. }
  34. }()
  35. return &Fluentd{
  36. Host: host,
  37. Port: port,
  38. Tag: tag,
  39. clog: clog,
  40. fluent: fluent,
  41. }
  42. }
  43. func (out *Fluentd) Post(time *time.Time, mtype string, message map[string]interface{}) {
  44. message["@timestamp"] = time.Format("2006-01-02T15:04:05.000Z07:00")
  45. message["type"] = mtype
  46. out.clog <- message
  47. }
  48. func (out *Fluentd) Close() {
  49. out.fluent.Close()
  50. }
  51. type OutputFile struct {
  52. Path string
  53. FileFormat string
  54. UID int
  55. GID int
  56. flog *os.File
  57. tnext *time.Time
  58. }
  59. func NewOutputFile(Path string, FileFormat string, UID int, GID int) Output {
  60. return &OutputFile{
  61. Path: Path,
  62. FileFormat: FileFormat,
  63. UID: UID,
  64. GID: GID,
  65. }
  66. }
  67. func (out *OutputFile) Post(ctime *time.Time, mtype string, message map[string]interface{}) {
  68. tz := time.Now()
  69. if out.tnext == nil || tz.After(*out.tnext) {
  70. flogFlag := os.O_APPEND | os.O_CREATE | os.O_WRONLY
  71. tnext := tz.Truncate(time.Hour).Add(time.Hour)
  72. fn := fmt.Sprintf("%s-%s.log", out.Path, tz.Format(out.FileFormat))
  73. flog, err := os.OpenFile(fn, flogFlag, 0644)
  74. if err != nil {
  75. panic(err)
  76. }
  77. flog.Chown(out.UID, out.GID)
  78. out.flog = flog
  79. out.tnext = &tnext
  80. }
  81. fmt.Fprintf(out.flog, "{\"@timestamp\":\"%s\"", ctime.Format("2006-01-02T15:04:05.000Z07:00"))
  82. message["type"] = mtype
  83. for k, v := range message {
  84. vstr, _ := json.Marshal(v)
  85. fmt.Fprintf(out.flog, ",\"%s\":%s", k, vstr)
  86. }
  87. fmt.Fprintln(out.flog, "}")
  88. }
  89. func (out *OutputFile) Close() {
  90. if out.flog != nil {
  91. out.flog.Close()
  92. }
  93. }
  94. type OutputStdOut struct {
  95. }
  96. func NewOutputStdOut() Output {
  97. return &OutputStdOut{}
  98. }
  99. func (out *OutputStdOut) Post(ctime *time.Time, mtype string, message map[string]interface{}) {
  100. fmt.Printf("%s ", ctime.Format("2006-01-02T15:04:05.000Z07:00"))
  101. message["type"] = mtype
  102. for k, v := range message {
  103. vstr, _ := json.Marshal(v)
  104. fmt.Printf(" %s:%s", k, vstr)
  105. }
  106. }
  107. func (out *OutputStdOut) Close() {
  108. }
  109. type DummyOutputData struct {
  110. Time time.Time
  111. Tag string
  112. Message map[string]interface{}
  113. }
  114. type DummyOutput struct {
  115. data []*DummyOutputData
  116. }
  117. func (out *DummyOutput) Post(ctime *time.Time, mtype string, message map[string]interface{}) {
  118. // fmt.Printf("LOG [%s]\n", message)
  119. message["type"] = mtype
  120. out.data = append(out.data, &DummyOutputData{Time: *ctime, Tag: mtype, Message: message})
  121. }
  122. func (out *DummyOutput) Close() {
  123. }
  124. func (out *DummyOutput) String() string {
  125. res := []string{}
  126. for _, v := range out.data {
  127. str, _ := json.MarshalIndent(v.Message, "", " ")
  128. res = append(res, string(str))
  129. }
  130. return strings.Join(res, "\n")
  131. }
  132. func (out *DummyOutput) Field(index int, field string) string {
  133. if index < len(out.data) {
  134. f := out.data[index].Message[field]
  135. if f != nil {
  136. if v, ok := f.(string); ok {
  137. return v
  138. }
  139. str, _ := json.MarshalIndent(f, "", " ")
  140. return string(str)
  141. }
  142. }
  143. return ""
  144. }