Reputation: 6238
I would like to get the application status of a running application. For example:
# start my app
./my_app
# require status
./my_app status
# it prints information about the application
jobs waiting in queue : 120
processing jobs : 3414
jobs done : 300
number of bad request received : 120
[...]
I see for the moment only one option to accomplish this result: using an external process.
The external process "speak" with the main application through a file (it touch
a new file, so the main application "knows" that it must prepare the status report), then when the status report is ready, it send back to the external process (through a file), finally this one print the status to the cli.
But personally I find this solution not so elegant.
Do you have any others ideas to accomplish this? The application is written in Golang, are there maybe any tricks in Go to do this?
Upvotes: 2
Views: 191
Reputation: 417767
The file system is not the only way to provide input for an application, there are many other ways, e.g. sending data to its standard input, the application may listen on a port for incoming connections or using any other peripherals (like microphone, sensors etc.).
Since Go has a built-in webserver, it may be convenient to take advantage of it: the Go app can start the webserver (if it doesn't yet use it), and listen on a port for incoming connections, and when requests come, simply send back the status as simple text or in HTML format.
Here is an example of it:
package main
import (
"fmt"
"net/http"
)
var (
waiting = 120
processing = 3414
done = 300
)
func ServeStats(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "%-22s : %d\n", "jobs waiting in queue", waiting)
fmt.Fprintf(w, "%-22s : %d\n", "processing jobs", processing)
fmt.Fprintf(w, "%-22s : %d\n", "jobs done", done)
}
func main() {
http.HandleFunc("/", ServeStats)
err := http.ListenAndServe("localhost:8081", nil)
if err != nil {
fmt.Println("An instance of the application is already running!",
"Provide the 'status' parameter to see stats.")
}
}
The process that wants to get the status of your running app only has to make an HTTP GET
request (e.g. wget in linux) to get the status. The above application serves the following status text as the response:
jobs waiting in queue : 120
processing jobs : 3414
jobs done : 300
Important note:
I started the webserver on address "localhost:8081"
which means the stats are only available from localhost (the same computer). If your app already uses the webserver, you may use that, but note that if it is reachable from the "outside" so will be your stats. If this is unwanted, you must check if the request (client) is originating from localhost, and if not you can deny serving the request.
The "external process" that queries the status doesn't even have to be external, you can implement it in the application itself.
Using your example: the application on startup can check if the status
command line argument is present, and if so, it will not continue the normal startup process but perform the HTTP GET
to get the status of the other running instance of the app, print it to the console and exit right after.
Here's how you can do it. The modified main()
function:
func main() {
if len(os.Args) > 1 && os.Args[1] == "status" {
getStatus()
return
}
http.HandleFunc("/", ServeStats)
err := http.ListenAndServe("localhost:8081", nil)
if err != nil {
fmt.Println("An instance of the application is already running!",
"Provide the 'status' parameter to see stats.")
}
}
And the implementation of getStatus()
:
func getStatus() {
resp, err := http.Get("http://localhost:8081/")
if err != nil {
fmt.Println("No running instance found!")
return
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
fmt.Println("Running instance found but failed to get status!")
return
}
fmt.Println("Status of the running instance:")
fmt.Println(string(body))
}
If you provide no arguments (or not the "status"
one), the application tries to start normally.
If you provide the argument "status"
, it tries to get the status from a running instance. If succeeds, prints the received status. If not, prints that there is no running instance found. Either way, run terminates after that.
Upvotes: 3