'Golang retrieve application uptime

I'm trying to retrieve the current uptime of my Go application.

I've seen there's a package syscall which provides a type Sysinfo_t and a method Sysinfo(*Sysinfo_t) which apparently allows you to retrieve the Uptime (since it's a field of the Sysinfo_t struct)

What I've done so far is:

sysi := &syscall.Sysinfo_t{}

if err := syscall.Sysinfo(sysi); err != nil {
    return http.StatusInternalServerError, nil
}

The problem is that at compile time I get this:

/path/to/file/res_system.go:43: undefined: syscall.Sysinfo_t
/path/to/file/res_system.go:45: undefined: syscall.Sysinfo

I've searched a bit and apparently that method and type are available only on Linux and I need the application to run both on Linux and OsX (which I'm currently using).

Is there a cross-compatible way to retrieve the application uptime?

NOTE: I'd rather not use any third party libraries (unless they're absolutely necessary)



Solution 1:[1]

Simple way to get uptime is to store service start time:

https://play.golang.org/p/by_nkvhzqD

package main

import (
    "fmt"
    "time"
)

var startTime time.Time

func uptime() time.Duration {
    return time.Since(startTime)
}

func init() {
    startTime = time.Now()
}

func main() {
    fmt.Println("started")

    time.Sleep(time.Second * 1)
    fmt.Printf("uptime %s\n", uptime())

    time.Sleep(time.Second * 5)
    fmt.Printf("uptime %s\n", uptime())
}

Solution 2:[2]

You should use Since function from time package.

create time value when application start:

startTime := time.Now()

then ask whenever you want:

uptime := time.Since(startTime)

Solution 3:[3]

Package syscall was frozen on Go 1.4.

NOTE: This package is locked down. Code outside the standard Go repository should be migrated to use the corresponding package in the golang.org/x/sys repository. That is also where updates required by new systems or versions should be applied. See https://golang.org/s/go1.4-syscall for more information.

Use Sysinfo from golang.org/x/sys it should support this in a cross-platform way, at least on Unix.

Solution 4:[4]

Difficulties

import "syscall" has been starved on most of its functionality which has been extracted to platform specific code in import "golang.org/x/sys/unix" and import "golang.org/x/sys/windows".

macOS GOOS==Darwin sorts under unix. The code in unix and windows is platform-specific, ie. if windows is imported on unix, the result is

error while importing golang.org/x/sys/windows: build constraints exclude all Go files in …

This means the program has to have a portable layer defining a portable function name, and that function is implemented for each supported platform like _darwin.go _linux.go and _windows.go which has to be tested on the real operating system.

The alternative is to use a third-party package where portability is already implemented. What you do then is to browse to Go Package search and pick a well-written candidate.

Solution

I browsed to Go Package search for Sysinfo: https://pkg.go.dev/search?q=sysinfo

Top result is gosysinfo "github.com/elastic/go-sysinfo". This package is awkwardly written as can be seen by a hyphen in its name and a peculiar package structure. It works, and the code goes like:

import (
  gosysinfo "github.com/elastic/go-sysinfo"
  "github.com/elastic/go-sysinfo/types"
  "github.com/haraldrudell/parl"
)

func goSysinfo() {
  var process types.Process
  var err error
  if process, err = gosysinfo.Self(); err != nil {
    panic(parl.Errorf("go-sysinfo.Self: %w", err))
  }
  var processInfo types.ProcessInfo
  if processInfo, err = process.Info(); err != nil {
    panic(parl.Errorf("go-sysinfo.Info: %w", err))
  }
  startTime := processInfo.StartTime
  fmt.Printf("Process start time: %s\n", startTime.Format(parl.Rfc3339s))
}
?
Process start time: 2022-03-22 10:15:05-07:00

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 fredmaggiowski
Solution 2 Melih Mucuk
Solution 3 toqueteos
Solution 4 Harald Rudell