Various adjustments
[pstop.git] / main.go
1 // Top like progream which collects information from MySQL's
2 // performance_schema database.
3 package main
4
5 import (
6         "database/sql"
7         "flag"
8         "fmt"
9         "log"
10         "os"
11         "os/signal"
12         "syscall"
13         "time"
14
15         _ "github.com/go-sql-driver/mysql"
16         "github.com/nsf/termbox-go"
17
18         "github.com/sjmudd/mysql_defaults_file"
19         "github.com/sjmudd/pstop/lib"
20         "github.com/sjmudd/pstop/state"
21         "github.com/sjmudd/pstop/version"
22 )
23
24 const (
25         sql_driver = "mysql"
26         db         = "performance_schema"
27 )
28
29 func get_db_handle() *sql.DB {
30         var err error
31         var dbh *sql.DB
32
33         dbh, err = mysql_defaults_file.OpenUsingDefaultsFile(sql_driver, "", "performance_schema")
34         if err != nil {
35                 log.Fatal(err)
36         }
37         if err = dbh.Ping(); err != nil {
38                 log.Fatal(err)
39         }
40
41         return dbh
42 }
43
44 // make chan for termbox events and run a poller to send events to the channel
45 // - return the channel
46 func new_tb_chan() chan termbox.Event {
47         termboxChan := make(chan termbox.Event)
48         go func() {
49                 for {
50                         termboxChan <- termbox.PollEvent()
51                 }
52         }()
53         return termboxChan
54 }
55
56 func usage() {
57         fmt.Println(lib.MyName() + " - " + lib.Copyright())
58         fmt.Println("")
59         fmt.Println("Top-like program to show MySQL activity by using information collected")
60         fmt.Println("from performance_schema.")
61         fmt.Println("")
62         fmt.Println("Usage: " + lib.MyName() + " <options>")
63         fmt.Println("")
64         fmt.Println("Options:")
65         fmt.Println("-help      show this help message")
66         fmt.Println("-version   show the version")
67 }
68
69 func main() {
70         var flag_version = flag.Bool("version", false, "Show the version of "+lib.MyName())
71         var flag_debug = flag.Bool("debug", false, "Enabling debug logging")
72         var flag_help = flag.Bool("help", false, "Provide some help for "+lib.MyName())
73         flag.Parse()
74
75         // clean me up
76         if *flag_debug {
77                 lib.Logger.EnableLogging(true)
78         }
79         if *flag_version {
80                 fmt.Println(lib.MyName() + " version " + version.Version())
81                 return
82         }
83         if *flag_help {
84                 usage()
85                 return
86         }
87
88         lib.Logger.Println("Starting " + lib.MyName())
89         var state state.State
90
91         interval := time.Second
92         sigChan := make(chan os.Signal, 1)
93         done := make(chan struct{})
94         defer close(done)
95         termboxChan := new_tb_chan()
96
97         signal.Notify(sigChan, syscall.SIGINT, syscall.SIGTERM)
98
99         ticker := time.NewTicker(interval) // generate a periodic signal
100
101         state.Setup(get_db_handle())
102
103         finished := false
104         for !finished {
105                 select {
106                 case <-done:
107                         fmt.Println("exiting")
108                         finished = true
109                 case sig := <-sigChan:
110                         fmt.Println("Caught a signal", sig)
111                         done <- struct{}{}
112                 case <-ticker.C:
113                         state.Collect()
114                         state.Display()
115                 case event := <-termboxChan:
116                         // switch on event type
117                         switch event.Type {
118                         case termbox.EventKey: // actions depend on key
119                                 switch event.Key {
120                                 case termbox.KeyCtrlZ, termbox.KeyCtrlC, termbox.KeyEsc:
121                                         finished = true
122                                 case termbox.KeyTab: // tab - change display modes
123                                         state.DisplayNext()
124                                         state.Display()
125                                 }
126                                 switch event.Ch {
127                                 case '-': // decrease the interval if > 1
128                                         if interval > time.Second {
129                                                 ticker.Stop()
130                                                 interval -= time.Second
131                                                 ticker = time.NewTicker(interval)
132                                         }
133                                 case '+': // increase interval by creating a new ticker
134                                         ticker.Stop()
135                                         interval += time.Second
136                                         ticker = time.NewTicker(interval)
137                                 case 'h': // help
138                                         state.SetHelp(!state.Help())
139                                 case 'q': // quit
140                                         finished = true
141                                 case 't': // toggle between absolute/relative statistics
142                                         state.SetWantRelativeStats(!state.WantRelativeStats())
143                                         state.Display()
144                                 case 'z': // reset the statistics to now by taking a query of current values
145                                         state.ResetDBStatistics()
146                                         state.Display()
147                                 }
148                         case termbox.EventResize: // set sizes
149                                 state.ScreenSetSize(event.Width, event.Height)
150                                 state.Display()
151                         case termbox.EventError: // quit
152                                 log.Fatalf("Quitting because of termbox error: \n%s\n", event.Err)
153                         }
154                 }
155         }
156         state.Cleanup()
157         ticker.Stop()
158         lib.Logger.Println("Terminating " + lib.MyName())
159 }