From d38bc6ef7c4b5a914e5c3e492c1efdc84944fbd1 Mon Sep 17 00:00:00 2001 From: Simon J Mudd Date: Mon, 15 Dec 2014 22:04:51 +0100 Subject: [PATCH] Add more command line docs + other cleanups --- README.md | 18 +++++-- i_s/pl_by_user.go | 4 -- i_s/processlist.go | 2 +- key_value_cache/key_value_cache.go | 15 ++++-- main.go | 79 +++++++++++++++++++++++++++--- version/version.go | 4 +- 6 files changed, 99 insertions(+), 23 deletions(-) diff --git a/README.md b/README.md index 44105b2..1bcf3b7 100644 --- a/README.md +++ b/README.md @@ -14,11 +14,23 @@ the actiity of those users. Install and update this go package with `go get -u github.com/sjmudd/pstop` +### Dependencies + +The following Non-core Go dependencies are: +* github.com/sjmudd/mysql_defaults_file for connecting to MySQL via +a defaults file. +* github.com/nsf/termbox-go a library for creating cross-platform +text-based interfaces. + ### Configuration -Access to MySQL is currently via a defaults-file which is assumed -to be `~/.my.cnf`. Alternatively you can now provide --defaults-file=/path/to/.my.cnf if needed. +Access to MySQL can be made by one of the following methods: +* Default: use a defaults-file named `~/.my.cnf`. +* use an explicit defaults-file with `--defaults-file=/path/to/.my.cnf`. +* connect to a host with `--host=somehost --port=999 --user=someuser --password=somepass`, or +* connect via a socket with `--socket=/path/to/mysql.sock --user=someuser --password=somepass` + +The user if not specified will default to the contents of `$USER`. ### Grants diff --git a/i_s/pl_by_user.go b/i_s/pl_by_user.go index 576045b..f5bd83f 100644 --- a/i_s/pl_by_user.go +++ b/i_s/pl_by_user.go @@ -126,10 +126,6 @@ func (t pl_by_user_rows) Sort() { sort.Sort(ByRunTime(t)) } -func (r pl_by_user_row) Description() string { - return "no description" -} - func (t pl_by_user_rows) emptyRowContent() string { var r pl_by_user_row return r.row_content(r) diff --git a/i_s/processlist.go b/i_s/processlist.go index 3c5c258..50d5e92 100644 --- a/i_s/processlist.go +++ b/i_s/processlist.go @@ -70,7 +70,7 @@ func (t Processlist) RowContent(max_rows int) []string { func (t Processlist) Description() string { count := t.count_rows() - return fmt.Sprintf("User Information (processlist) %d rows", count) + return fmt.Sprintf("Activity by Username (processlist) %d rows", count) } func (t Processlist) count_rows() int { diff --git a/key_value_cache/key_value_cache.go b/key_value_cache/key_value_cache.go index e5881b6..9b689a2 100644 --- a/key_value_cache/key_value_cache.go +++ b/key_value_cache/key_value_cache.go @@ -1,3 +1,7 @@ +// key_value_cache provides an extremely simple string key to value cache. +// This is used to reduce the number of lookups from MySQL filename +// to the equivalent table or logical name given the conversion +// routines to do this use many regexps and this is quite expensive. package key_value_cache import ( @@ -12,15 +16,14 @@ type KeyValueCache struct { read_requests, served_from_cache, write_requests int } -// create a new KeyValueCache entry +// Create a new KeyValueCache entry. func NewKeyValueCache() KeyValueCache { lib.Logger.Println("KeyValueCache()") - var kvc KeyValueCache - return kvc + return KeyValueCache {} } -// return value if found +// Given a lookup key return the value if found. func (kvc *KeyValueCache) Get(key string) (result string, err error) { lib.Logger.Println("KeyValueCache.Get(", key, ")") if kvc.cache == nil { @@ -43,13 +46,15 @@ func (kvc *KeyValueCache) Get(key string) (result string, err error) { } } -// write to cache and return value +// Write to cache and return the value saved. func (kvc *KeyValueCache) Put(key, value string) string { lib.Logger.Println("KeyValueCache.Put(", key, ",", value, ")") kvc.cache[key] = value return value } +// Provide some staticts on read and write requests and the number +// of requests served from cache. func (kvc *KeyValueCache) Statistics() (int, int, int) { return kvc.read_requests, kvc.served_from_cache, kvc.write_requests } diff --git a/main.go b/main.go index 53960f2..94c0036 100644 --- a/main.go +++ b/main.go @@ -34,6 +34,11 @@ var ( flag_debug = flag.Bool("debug", false, "Enabling debug logging") flag_defaults_file = flag.String("defaults-file", "", "Provide a defaults-file to use to connect to MySQL") flag_help = flag.Bool("help", false, "Provide some help for "+lib.MyName()) + flag_host = flag.String("host", "", "Provide the hostname of the MySQL to connect to") + flag_port = flag.Int("port", 0 , "Provide the port number of the MySQL to connect to (default: 3306)") /* deliberately 0 here, defaults to 3306 elsewhere */ + flag_socket = flag.String("socket", "", "Provide the path to the local MySQL server to connect to") + flag_password = flag.String("password", "", "Provide the password when connecting to the MySQL server") + flag_user = flag.String("user", "", "Provide the username to connect with to MySQL (default: $USER)") flag_version = flag.Bool("version", false, "Show the version of "+lib.MyName()) cpuprofile = flag.String("cpuprofile", "", "write cpu profile to file") @@ -41,10 +46,10 @@ var ( ) // Connect to the database with the given defaults-file, or ~/.my.cnf if not provided. -func get_db_handle( defaults_file string ) *sql.DB { +func connect_by_defaults_file( defaults_file string ) *sql.DB { var err error var dbh *sql.DB - lib.Logger.Println("get_db_handle() connecting to database") + lib.Logger.Println("connect_by_defaults_file() connecting to database") dbh, err = mysql_defaults_file.OpenUsingDefaultsFile(sql_driver, defaults_file, "performance_schema") if err != nil { @@ -57,6 +62,24 @@ func get_db_handle( defaults_file string ) *sql.DB { return dbh } +// connect to MySQL using various component parts needed to make the dsn +func connect_by_components( components map[string]string ) *sql.DB { + var err error + var dbh *sql.DB + lib.Logger.Println("connect_by_components() connecting to database") + + new_dsn := mysql_defaults_file.BuildDSN(components, "performance_schema") + dbh, err = sql.Open(sql_driver, new_dsn) + if err != nil { + log.Fatal(err) + } + if err = dbh.Ping(); err != nil { + log.Fatal(err) + } + + return dbh +} + // make chan for termbox events and run a poller to send events to the channel // - return the channel func new_tb_chan() chan termbox.Event { @@ -78,9 +101,14 @@ func usage() { fmt.Println("Usage: " + lib.MyName() + " ") fmt.Println("") fmt.Println("Options:") - fmt.Println("-defaults-file=/path/to/defaults.file Connect to MySQL using given defaults-file" ) - fmt.Println("-help show this help message") - fmt.Println("-version show the version") + fmt.Println("--defaults-file=/path/to/defaults.file Connect to MySQL using given defaults-file" ) + fmt.Println("--help Show this help message") + fmt.Println("--version Show the version") + fmt.Println("--host= MySQL host to connect to") + fmt.Println("--port= MySQL port to connect to") + fmt.Println("--socket= MySQL path of the socket to connect to") + fmt.Println("--user= User to connect with") + fmt.Println("--password= Password to use when connecting") } // pstop requires MySQL 5.6+ or MariaDB 10.0+. Check the version @@ -149,11 +177,46 @@ func main() { lib.Logger.Println("Starting " + lib.MyName()) - if flag_defaults_file != nil && *flag_defaults_file != "" { - defaults_file = *flag_defaults_file + var dbh *sql.DB + + if *flag_host != "" || *flag_socket != "" { + lib.Logger.Println("--host= or --socket= defined") + var components = make(map[string]string) + if *flag_host != "" && *flag_socket != "" { + fmt.Println(lib.MyName() + ": Do not specify --host and --socket together" ) + os.Exit(1) + } + if *flag_host != "" { + components["host"] = *flag_host + } + if *flag_port != 0 { + if *flag_socket == "" { + components["port"] = fmt.Sprintf("%d", *flag_port) + } else { + fmt.Println(lib.MyName() + ": Do not specify --socket and --port together" ) + os.Exit(1) + } + } + if *flag_socket != "" { + components["socket"] = *flag_socket + } + if *flag_user != "" { + components["user"] = *flag_user + } + if *flag_password != "" { + components["password"] = *flag_password + } + dbh = connect_by_components( components ) + } else { + if flag_defaults_file != nil && *flag_defaults_file != "" { + lib.Logger.Println("--defaults-file defined") + defaults_file = *flag_defaults_file + } else { + lib.Logger.Println("connecting by implicit defaults file") + } + dbh = connect_by_defaults_file( defaults_file ) } - dbh := get_db_handle( defaults_file ) if err := validate_mysql_version(dbh); err != nil { log.Fatal(err) } diff --git a/version/version.go b/version/version.go index be253eb..74ffa65 100644 --- a/version/version.go +++ b/version/version.go @@ -1,8 +1,8 @@ -// package to return the package version +// package to return the program version package version const ( - version = "0.1.3" + version = "0.1.4" ) // return the current application version -- 2.20.1