main.go 2.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106
  1. package main
  2. import (
  3. "flag"
  4. "fmt"
  5. "log"
  6. "net"
  7. "net/url"
  8. "os"
  9. "os/signal"
  10. "strconv"
  11. "time"
  12. "git.lattuga.net/boyska/circolog/formatter"
  13. "github.com/gorilla/websocket"
  14. "gopkg.in/mcuadros/go-syslog.v2/format"
  15. "gopkg.in/mgo.v2/bson"
  16. )
  17. func main() {
  18. addr := flag.String("addr", "localhost:9080", "http service address")
  19. querySocket := flag.String("socket", "", "Path to a unix domain socket for the HTTP server")
  20. backlogLimit := flag.Int("n", -1, "Limit the backlog length, defaults to no limit (-1)")
  21. flag.Parse()
  22. interrupt := make(chan os.Signal, 1)
  23. signal.Notify(interrupt, os.Interrupt)
  24. var d *websocket.Dialer
  25. u := url.URL{Scheme: "ws",
  26. Host: *addr, // ignored in case of -socket; see the Dialer below
  27. Path: "/ws",
  28. }
  29. q := u.Query()
  30. q.Set("fmt", "bson")
  31. if *backlogLimit >= 0 {
  32. q.Set("l", strconv.Itoa(*backlogLimit))
  33. }
  34. u.RawQuery = q.Encode()
  35. if *querySocket != "" {
  36. d = &websocket.Dialer{
  37. NetDial: func(network, addr string) (net.Conn, error) {
  38. return net.Dial("unix", *querySocket)
  39. },
  40. HandshakeTimeout: 45 * time.Second, // same as DefaultDialer
  41. }
  42. log.Printf("connecting to %s", *querySocket)
  43. } else {
  44. d = websocket.DefaultDialer
  45. log.Printf("connecting to %s", *addr)
  46. }
  47. c, _, err := d.Dial(u.String(), nil)
  48. if err != nil {
  49. log.Fatal("dial:", err)
  50. }
  51. defer c.Close()
  52. log.Println("connected!", u.String())
  53. done := make(chan struct{})
  54. go func() {
  55. defer close(done)
  56. for {
  57. _, serialized, err := c.ReadMessage()
  58. if err != nil {
  59. log.Println("close:", err)
  60. return
  61. }
  62. var parsed format.LogParts
  63. if err := bson.Unmarshal(serialized, &parsed); err != nil {
  64. log.Println("invalid YAML", err)
  65. continue
  66. }
  67. if err := formatter.WriteFormatted(os.Stdout, formatter.FormatSyslog, parsed); err != nil {
  68. log.Println("error printing", err)
  69. }
  70. fmt.Println()
  71. }
  72. }()
  73. for {
  74. select {
  75. case <-done:
  76. return
  77. case <-interrupt:
  78. log.Println("interrupt")
  79. // Cleanly close the connection by sending a close message and then waiting (with timeout) for the
  80. // server to close the connection.
  81. err := c.WriteMessage(websocket.CloseMessage, websocket.FormatCloseMessage(websocket.CloseNormalClosure, ""))
  82. if err != nil {
  83. log.Println("write close:", err)
  84. return
  85. }
  86. select {
  87. case <-done:
  88. log.Println("Successfully close")
  89. case <-time.After(1 * time.Second):
  90. log.Println("Forced close")
  91. }
  92. return
  93. }
  94. }
  95. }