Tutorial: Server Monitor
In this tutorial, we will build a functional Server Monitor application. You will learn how to register Views, use the Router, handle global Keyboard inputs, and utilize the built-in Logger—all in one smooth flow.
1. Setting up the App
First, let's create our main.go file and initialize the Tako framework.
package main
import (
"gettako.dev/tako"
"gettako.dev/tako/contracts"
)
func main() {
app := tako.NewApp()
// We will register our routes here shortly
tako.Run(app)
}
tako.Run(app) automatically handles booting providers, resolving the TUI manager, and starting the event loop!2. Creating the Dashboard View
In Tako, everything drawn on the screen is a View. A View only needs to implement a single Render(ctx) method. Let's create our Dashboard.
type DashboardScreen struct {
serverStatus string
}
func (s *DashboardScreen) Render(ctx contracts.Context) string {
return "=== SERVER MONITOR ===\n\n" +
"Status: " + s.serverStatus + "\n\n" +
"[P] Ping Server | [Q] Quit"
}
3. Registering the Route
Now that we have our DashboardScreen, we need to tell Tako's Router about it. Let's update our main.go file.
func main() {
app := tako.NewApp()
// Register the "dashboard" route
app.TUI().Router().Route("dashboard", func() contracts.View {
return &DashboardScreen{
serverStatus: "Idle",
}
})
// Tell the router to start on this screen
app.TUI().Router().Navigate("dashboard")
tako.Run(app)
}
If you run go run main.go right now, you will see your Dashboard! But pressing P or Q doesn't do anything yet.
4. Handling Global Inputs
Let's make our app interactive. We want Q to quit the app, and P to simulate pinging the server. We can do this using the Input().Global() manager.
func main() {
app := tako.NewApp()
// ... (routing code) ...
// Bind Q and Ctrl+C to quit
app.Input().Global().BindAny([]string{"q", "ctrl+c"}, func(ctx contracts.InputContext) {
ui, _ := contracts.Resolve[contracts.UIManager](app, "ui.manager")
ui.Quit()
})
// Bind P to Ping
app.Input().Global().Bind("p", func(ctx contracts.InputContext) {
app.Logger().Info("Ping requested by user!")
// In a real app, you would dispatch an event or update state here
app.Events().Dispatch("server.pinged", nil)
})
tako.Run(app)
}
P to work on the Dashboard, you would make DashboardScreen implement the contracts.KeyBinder interface instead!5. Adding the Logger
Did you notice we called app.Logger().Info() above?
Because TUIs take over your entire terminal screen, using fmt.Println will completely break your layout. Tako includes an asynchronous, file-based Logger out of the box.
Run your app, press P, and then press Q to exit.
Now, look in your project directory. You will see a hidden folder .tako/logs/tako.log. Open it, and you'll see your perfectly formatted log entry!
time=2024-05-12T10:00:00.000Z level=INFO msg="Ping requested by user!"
Conclusion
Congratulations! 🎉
In just a few lines of code, you have built a TUI app with routing, keybindings, event dispatching, and file-logging.
Next, check out Architecture Concepts to understand how Tako achieves this magic under the hood.
