PACKAGE DOCUMENTATION package kstat import "github.com/siebenmann/go-kstat" Package kstat provides a Go interface to the Solaris/OmniOS kstat(s) system for user-level access to a lot of kernel statistics. For more documentation on kstats, see kstat(1) and kstat(3kstat). The package can retrieve what are called 'named' kstat statistics, IO statistics, and the most common additional types of 'raw' statistics, which covers almost all kstats you will normally find in the kernel. You can see the names and types of other kstats, but not currently retrieve data for them. Named statistics are the most common type for general information; IO statistics are exported by disks and some other things. Supported additional raw kstats are unix:0:sysinfo, unix:0:vminfo, unix:0:var, and mnt:*:mntinfo. General usage for named statistics: call Open() to obtain a Token, then call GetNamed() on it to obtain Named(s) for specific statistics. Note that this always gives you the very latest value for the statistic. If you want a number of statistics from the same module:inst:name triplet (eg several network counters from the same network interface) and you want them to all have been gathered at the same time, you need to call .Lookup() to obtain a KStat and then repeatedly call its .GetNamed() (this is also slightly more efficient). The short version: a kstat is a collection of some related statistics, eg various network counters for a particular network interface. A Token is a handle for a collection of kstats. You go collection (Token) -> kstat (KStat) -> specific statistic (Named) in order to retrieve the value of a specific statistic. (IO stats are retrieved all at once with GetIO(), because they come to us from the kernel as one single struct so that's what you get.) This is a cgo-based package. Cross compilation is up to you. Goroutine safety is in no way guaranteed because the underlying C kstat library is probably not thread or goroutine safe (and there are some all-Go concurrency races involving .Close()). This package may leak memory, especially since the Solaris kstat manpage is not clear on the requirements here. However I believe it's reasonably memory safe. It's possible to totally corrupt memory with use-after-free errors if you do operations on kstats after calling Token.Close(), although we try to avoid that. NOTE: this package is quite young. The API may well change as I (and other people) gain more experience with it. PERFORMANCE In general this is not going to be as lean and mean as calling C directly, partly because of intrinsic CGo overheads and partly because we do more memory allocation and deallocation than a C program would (partly because we prioritize not leaking memory). SUPPORTED AND UNSUPPORTED KSTAT TYPES We support named kstats and IO kstats (KSTAT_TYPE_NAMED and KSTAT_TYPE_IO / kstat_io_t respectively). kstat(1) also knows about a number of magic specific 'raw' stats (which are generally custom C structs); of these we support unix:0:sysinfo, unix:0:vminfo, unix:0:var, and mnt:*:mntinfo for NFS filesystem mounts. In theory kstat supports general timer and interrupt stats. In practice there is no use of KSTAT_TYPE_TIMER in the current Illumos kernel source and very little use of KSTAT_TYPE_INTR (mostly by very old hardware drivers, although the vioif driver uses it too). Since I can't test KSTAT_TYPE_INTR stats, we don't currently support it. There are also a few additional KSTAT_TYPE_RAW raw stats that we don't support, mostly because they seem to be effectively obsolete. These specific raw stats can be found listed in the Illumos source code in cmd/stat/kstat/kstat.h in the ks_raw_lookup array. See cmd/stat/kstat/kstat.c for how they're interpreted. If you need access to one of these kstats, the KStat.CopyTo() and KStat.Raw() methods give you an escape hatch to roll your own. You'll probably need to use cgo to generate an appropriate Go struct that matches the C struct you need. My notes on this process may be helpful: https://utcc.utoronto.ca/~cks/space/blog/programming/GoCGoCompatibleStructs Author: Chris Siebenmann https://github.com/siebenmann/go-kstat Copyright: standard Go copyright. (If you're reading this documentation on a non-Solaris platform, you're probably not seeing the detailed API documentation for constants, types, and so on because of tooling limitations in godoc et al.) FUNCTIONS func CFieldString(src []int8) string CFieldString converts a (null-terminated) C string embedded in an []int8 slice to a (Go) string. The []int8 slice is likely to come from an [N]int8 fixed-size field in a statistics struct. If there is no null in the slice, the entire slice is returned. (The no-null behavior is common in C APIs; a string is often allowed to exactly fill the field with no room for a trailing null.) TYPES type IO struct { Nread uint64 Nwritten uint64 Reads uint32 Writes uint32 Wtime int64 Wlentime int64 Wlastupdate int64 Rtime int64 Rlentime int64 Rlastupdate int64 Wcnt uint32 Rcnt uint32 } IO represents the entire collection of KStat (disk) IO statistics exposed by an IoStat type KStat. Because IO is an exact copy of the C kstat_io_t structure from the kernel, it does not have a Snaptime or KStat field. You must save that information separately if you need it, perhaps by embedded the IO struct as an anonymous struct in an additional struct of your own. type KSType int KSType is the type of the data in a KStat. const ( RawStat KSType = C.KSTAT_TYPE_RAW NamedStat KSType = C.KSTAT_TYPE_NAMED IntrStat KSType = C.KSTAT_TYPE_INTR IoStat KSType = C.KSTAT_TYPE_IO TimerStat KSType = C.KSTAT_TYPE_TIMER ) The different types of data that a KStat may contain, ie these are the value of a KStat.Type. We currently only support getting Named and IO statistics. func (tp KSType) String() string type KStat struct { Module string Instance int Name string // Class is eg 'net' or 'disk'. In kstat(1) it shows up as a // ':class' statistic. Class string // Type is the type of kstat. Type KSType // Creation time of a kstat in nanoseconds since sometime. // See gethrtime(3) and kstat(3kstat). Crtime int64 // Snaptime is what kstat(1) reports as 'snaptime', the time // that this data was obtained. As with Crtime, it is in // nanoseconds since some arbitrary point in time. // Snaptime may not be valid until .Refresh() or .GetNamed() // has been called. Snaptime int64 // contains filtered or unexported fields } KStat is the access handle for the collection of statistics for a particular module:instance:name kstat. func (k *KStat) AllNamed() ([]*Named, error) AllNamed returns an array of all named statistics for a particular named-type KStat. Entries are returned in no particular order. func (k *KStat) CopyTo(ptr interface{}) error CopyTo copies a RawStat KStat into a struct that you supply a pointer to. The size of the struct must exactly match the size of the RawStat's data. CopyStat imposes conditions on the struct that you are copying to: it must be composed entirely of primitive integer types with defined sizes (intN and uintN), or arrays and structs that ultimately only contain them. All fields should be exported. If you give CopyStat a bad argument, it generally panics. This API is provisional and may be changed or deleted. func (k *KStat) GetIO() (*IO, error) GetIO retrieves the IO statistics data from an IoStat type KStat. It always refreshes the KStat to provide current data. It corresponds to kstat_read() followed by getting a copy of ks_data (which is a kstat_io_t). func (k *KStat) GetMntinfo() (*Mntinfo, error) GetMntinfo retrieves a Mntinfo struct from a nfs:*:mntinfo KStat. It does not force a refresh of the KStat. func (k *KStat) GetNamed(name string) (*Named, error) GetNamed obtains a particular named statistic from a KStat. It does not refresh the KStat's statistics data, so multiple calls to GetNamed on a single KStat will get a coherent set of statistic values from it. It corresponds to kstat_data_lookup(). func (k *KStat) Raw() (*Raw, error) Raw returns the raw byte data of a KStat. It may be called on any KStat. It does not refresh the KStat's data. func (k *KStat) Refresh() error Refresh the statistics data for a KStat. Note that this does not update any existing Named objects for statistics from this KStat. You must re-do .GetNamed() to get new ones in order to see any updates. Under the hood this does a kstat_read(). You don't need to call it explicitly before obtaining statistics from a KStat. func (k *KStat) String() string func (k *KStat) Valid() bool Valid returns true if a KStat is still valid after a Token.Update() call has returned true. If a KStat becomes invalid after an update, its fields remain available but you can no longer call methods on it. You may be able to look it up again with token.Lookup(k.Module, k.Instance, k.Name), although it's possible that the module:instance:name now refers to something else. Even if it is still the same thing, there is no continuity in the actual statistics once Valid becomes false; you must restart tracking from scratch. (For example, if one disk is removed from the system and another is added, the new disk may use the same module:instance:name as some of the old disk's KStats. Your .Lookup() may succeed, but what you get back is not in any way a continuation of the old disk's information.) Valid also returns false after the KStat's token has been closed. type Mntinfo struct { RProto [128]int8 Vers uint32 Flags uint32 Secmod uint32 Curread uint32 Curwrite uint32 Timeo int32 Retrans int32 Acregmin uint32 Acregmax uint32 Acdirmin uint32 Acdirmax uint32 Timers [4]struct { Srtt uint32 Deviate uint32 Rtxcur uint32 } Noresponse uint32 Failover uint32 Remap uint32 RCurserver [257]int8 // contains filtered or unexported fields } Mntinfo is the kernel data from nfs:*:mntinfo, which is a 'struct mntinfo_kstat'. Use .Proto() and .Curserver() to get the RProto and RCurserver fields as strings instead of their awkward raw form. func (m Mntinfo) Curserver() string Curserver returns a Mntinfo RCurserver as a string. func (m Mntinfo) Proto() string Proto returns a Mntinfo RProto as a string. type Named struct { Name string Type NamedType // Only one of the following values is valid; the others are zero // values. // // StringVal holds the value for both CharData and String Type(s). StringVal string IntVal int64 UintVal uint64 // The Snaptime this Named was obtained. Note that while you // use the parent KStat's Crtime, you cannot use its Snaptime. // The KStat may have been refreshed since this Named was // created, which updates the Snaptime. Snaptime int64 // Pointer to the parent KStat, for access to the full name // and the crtime associated with this Named. KStat *KStat } Named represents a particular kstat named statistic, ie the full module:instance:name:statistic and its current value. Name and Type are always valid, but only one of StringVal, IntVal, or UintVal is valid for any particular statistic; which one is valid is determined by its Type. Generally you'll already know what type a given named kstat statistic is; I don't believe Solaris changes their type once they're defined. func (ks *Named) String() string type NamedType int NamedType represents the various types of named kstat statistics. const ( CharData NamedType = C.KSTAT_DATA_CHAR Int32 NamedType = C.KSTAT_DATA_INT32 Uint32 NamedType = C.KSTAT_DATA_UINT32 Int64 NamedType = C.KSTAT_DATA_INT64 Uint64 NamedType = C.KSTAT_DATA_UINT64 String NamedType = C.KSTAT_DATA_STRING ) The different types of data that a named kstat statistic can be (ie, these are the potential values of Named.Type). func (tp NamedType) String() string type Raw struct { Data []byte Ndata uint64 Snaptime int64 KStat *KStat } Raw is the raw data of a KStat. The actual bytes are in Data; Ndata is kstat_t.ks_ndata, and is not normally useful. Note that with RawStat KStats, it turns out that Ndata == len(Data). This is contrary to its meaning for other types of kstats. type Sysinfo struct { Updates uint32 Runque uint32 Runocc uint32 Swpque uint32 Swpocc uint32 Waiting uint32 } Sysinfo is the data from unix:0:sysinfo, which is a sysinfo_t. type Token struct { // contains filtered or unexported fields } Token is an access token for obtaining kstats. func Open() (*Token, error) Open returns a kstat Token that is used to obtain kstats. It corresponds to kstat_open(). You should call .Close() when you're done and then not use any KStats or Nameds obtained through this token. (Failing to call .Close() will cause memory leaks.) func (t *Token) All() []*KStat All returns an array of all available KStats. (It has no error return because due to how kstats are implemented, it cannot fail.) func (t *Token) Close() error Close a kstat access token. A closed token cannot be used for anything and cannot be reopened. After a Token has been closed it remains safe to look at fields on KStat and Named objects obtained through the Token, but it is not safe to call methods on them other than String(); doing so may cause memory corruption, although we try to avoid that. This corresponds to kstat_close(). func (t *Token) GetNamed(module string, instance int, name, stat string) (*Named, error) GetNamed obtains the Named representing a particular (named) kstat module:instance:name:statistic statistic. It always returns current data for the kstat statistic, even if it's called repeatedly for the same statistic. It is equivalent to .Lookup() then KStat.GetNamed(). func (t *Token) Lookup(module string, instance int, name string) (*KStat, error) Lookup looks up a particular kstat. module and name may be "" and instance may be -1 to mean 'the first one that kstats can find'. It also refreshes (or retrieves) the kstat's data and thus sets Snaptime. Lookup() corresponds to kstat_lookup() *plus kstat_read()*. func (tok *Token) Sysinfo() (*KStat, *Sysinfo, error) Sysinfo returns the KStat and the statistics from unix:0:sysinfo. It always returns a current, refreshed copy. func (t *Token) Update() (bool, error) Update synchronizes the Token to the current state of available kernel kstats, returning true if the kernel's list of available kstats changed and false otherwise. If there have been no changes in the kernel's kstat list, all KStats remain valid. If there was a kstat update, some or all of the KStats obtained through the Token may now be invalid. Some of the now-invalid KStats may still exist and be the same thing, but if so they will have to be looked up again. (This happens if, for example, a device disappears and then reappears. At the kernel level, the device's kstat is deleted when it disappears and then is recreated when it reappears; the kernel considers the recreated version to be a different kstat, although it has the same module:instance:name. Note that the same module:instance:name still existing does not guarantee that the kstat is for the same thing; one disk might have removed and then an entirely different new disk added.) Update corresponds to kstat_chain_update(). func (tok *Token) Var() (*KStat, *Var, error) Var returns the KStat and the statistics from unix:0:var. It always returns a current, refreshed copy. func (tok *Token) Vminfo() (*KStat, *Vminfo, error) Vminfo returns the KStat and the statistics from unix:0:vminfo. It always returns a current, refreshed copy. type Var struct { Buf int32 Call int32 Proc int32 Maxupttl int32 Nglobpris int32 Maxsyspri int32 Clist int32 Maxup int32 Hbuf int32 Hmask int32 Pbuf int32 Sptmap int32 Maxpmem int32 Autoup int32 Bufhwm int32 } Var is the data from unix:0:var, which is a 'struct var'. type Vminfo struct { Freemem uint64 Resv uint64 Alloc uint64 Avail uint64 Free uint64 Updates uint64 } Vminfo is the data from unix:0:vminfo, which is a vminfo_t. SUBDIRECTORIES cmd gen