456 lines
17 KiB
Plaintext
456 lines
17 KiB
Plaintext
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
|
|
|