Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,9 @@ When running (by privileged user) along-side active SMB server, `smbmetrics`
exports a set of gauge metrics over HTTP via port `9922`. Most metrics become
visible only when active SMB connections exists. When Samba is compiled and
run with profile-information enabled (`smb.conf` global section has
`smbd profiling level = on`), you may run `smbmetrics --profile` to export also
various profile stats as Prometheus metrics. Execute the folowing `curl`
command on the same machine where you run `smbmetrics` instance:
`smbd profiling level = on`), `smbmetrics` will also export various profile
stats as Prometheus metrics. Execute the following `curl` command on the same
machine where you run `smbmetrics` instance:

```console
$ curl --request GET "http://localhost:9922/metrics"
Expand Down
8 changes: 4 additions & 4 deletions cmd/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,9 @@ func main() {
var port int
pflag.IntVar(&port, "port", metrics.DefaultMetricsPort,
"Prometheus metrics-exporter port number")
var profile bool
pflag.BoolVar(&profile, "profile", false,
"Run with collect profile information enabled")
var noProfile bool
pflag.BoolVar(&noProfile, "no-profile", false,
"Run without collecting profile information")
pflag.Parse()

log := zap.New(zap.UseDevMode(true))
Expand Down Expand Up @@ -57,7 +57,7 @@ func main() {
}
log.Info("Located smbstatus", "path", loc, "version", ver)

err = metrics.RunSmbMetricsExporter(log, port, profile)
err = metrics.RunSmbMetricsExporter(log, port, !noProfile)
if err != nil {
os.Exit(1)
}
Expand Down
133 changes: 69 additions & 64 deletions internal/metrics/collectors.go
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ type smbStatusCollector struct {
}

func (col *smbStatusCollector) Collect(ch chan<- prometheus.Metric) {
smbInfo, err := NewUpdatedSMBInfo()
smbInfo, err := NewUpdatedSMBInfo(col.sme.log)
if err != nil {
return
}
Expand Down Expand Up @@ -151,70 +151,75 @@ type smbProfileCollector struct {
smbCollector
}

//nolint:funlen
func (col *smbProfileCollector) Collect(ch chan<- prometheus.Metric) {
if col.sme.profile {
smbProfileInfo, err := NewUpdatedSMBProfileInfo()
if err == nil {
smb2Calls := smbProfileInfo.profileStatus.SMB2Calls
ch <- col.smb2RequestMetric(&smb2Calls.NegProt, "negprot")
ch <- col.smb2RequestMetric(&smb2Calls.SessSetup, "sesssetup")
ch <- col.smb2RequestMetric(&smb2Calls.LogOff, "logoff")
ch <- col.smb2RequestMetric(&smb2Calls.Tcon, "tcon")
ch <- col.smb2RequestMetric(&smb2Calls.Tdis, "tdis")
ch <- col.smb2RequestMetric(&smb2Calls.Create, "create")
ch <- col.smb2RequestMetric(&smb2Calls.Close, "close")
ch <- col.smb2RequestMetric(&smb2Calls.Flush, "flush")
ch <- col.smb2RequestMetric(&smb2Calls.Read, "read")
ch <- col.smb2RequestMetric(&smb2Calls.Write, "write")
ch <- col.smb2RequestMetric(&smb2Calls.Lock, "lock")
ch <- col.smb2RequestMetric(&smb2Calls.Ioctl, "ioctl")
ch <- col.smb2RequestMetric(&smb2Calls.Cancel, "cancel")
ch <- col.smb2RequestMetric(&smb2Calls.KeepAlive, "keepalive")
ch <- col.smb2RequestMetric(&smb2Calls.Find, "find")
ch <- col.smb2RequestMetric(&smb2Calls.Notify, "notify")
ch <- col.smb2RequestMetric(&smb2Calls.GetInfo, "getinfo")
ch <- col.smb2RequestMetric(&smb2Calls.SetInfo, "setinfo")
ch <- col.smb2RequestMetric(&smb2Calls.Break, "break")

sysCalls := smbProfileInfo.profileStatus.SystemCalls
ch <- col.vfsIORequestMetric(&sysCalls.PRead, "pread")
ch <- col.vfsIORequestMetric(&sysCalls.AsysPRead, "asys_pread")
ch <- col.vfsIORequestMetric(&sysCalls.PWrite, "pwrite")
ch <- col.vfsIORequestMetric(&sysCalls.AsysPWrite, "asys_pwrite")
ch <- col.vfsIORequestMetric(&sysCalls.AsysFSync, "asys_fsync")

ch <- col.vfsRequestMetric(&sysCalls.Opendir, "opendir")
ch <- col.vfsRequestMetric(&sysCalls.FDOpendir, "fdopendir")
ch <- col.vfsRequestMetric(&sysCalls.Readdir, "readdir")
ch <- col.vfsRequestMetric(&sysCalls.Rewinddir, "rewinddir")
ch <- col.vfsRequestMetric(&sysCalls.Mkdirat, "mkdirat")
ch <- col.vfsRequestMetric(&sysCalls.Closedir, "closedir")
ch <- col.vfsRequestMetric(&sysCalls.Open, "open")
ch <- col.vfsRequestMetric(&sysCalls.OpenAt, "openat")
ch <- col.vfsRequestMetric(&sysCalls.CreateFile, "createfile")
ch <- col.vfsRequestMetric(&sysCalls.Close, "close")
ch <- col.vfsRequestMetric(&sysCalls.Lseek, "lseek")
ch <- col.vfsRequestMetric(&sysCalls.RenameAt, "renameat")
ch <- col.vfsRequestMetric(&sysCalls.Stat, "stat")
ch <- col.vfsRequestMetric(&sysCalls.FStat, "fstat")
ch <- col.vfsRequestMetric(&sysCalls.LStat, "lstat")
ch <- col.vfsRequestMetric(&sysCalls.FStatAt, "fstatat")
ch <- col.vfsRequestMetric(&sysCalls.UnlinkAt, "unlinkat")
ch <- col.vfsRequestMetric(&sysCalls.Chmod, "chmod")
ch <- col.vfsRequestMetric(&sysCalls.FChmod, "fchmod")
ch <- col.vfsRequestMetric(&sysCalls.FChown, "fchown")
ch <- col.vfsRequestMetric(&sysCalls.LChown, "lchown")
ch <- col.vfsRequestMetric(&sysCalls.Chdir, "chdir")
ch <- col.vfsRequestMetric(&sysCalls.GetWD, "getwd")
ch <- col.vfsRequestMetric(&sysCalls.Fntimes, "fntimes")
ch <- col.vfsRequestMetric(&sysCalls.FTruncate, "ftruncate")
ch <- col.vfsRequestMetric(&sysCalls.FAllocate, "fallocate")
ch <- col.vfsRequestMetric(&sysCalls.ReadLinkAt, "readlinkat")
ch <- col.vfsRequestMetric(&sysCalls.SymLinkAt, "symlinkat")
ch <- col.vfsRequestMetric(&sysCalls.LinkAt, "linkat")
ch <- col.vfsRequestMetric(&sysCalls.MknodAt, "mknodat")
ch <- col.vfsRequestMetric(&sysCalls.RealPath, "realpath")
}
if !col.sme.profile {
return
}
smbProfileInfo, err := NewUpdatedSMBProfileInfo(col.sme.log)
if err != nil {
return
}
smb2Calls := smbProfileInfo.profileStatus.SMB2Calls
if smb2Calls != nil {
ch <- col.smb2RequestMetric(&smb2Calls.NegProt, "negprot")
ch <- col.smb2RequestMetric(&smb2Calls.SessSetup, "sesssetup")
ch <- col.smb2RequestMetric(&smb2Calls.LogOff, "logoff")
ch <- col.smb2RequestMetric(&smb2Calls.Tcon, "tcon")
ch <- col.smb2RequestMetric(&smb2Calls.Tdis, "tdis")
ch <- col.smb2RequestMetric(&smb2Calls.Create, "create")
ch <- col.smb2RequestMetric(&smb2Calls.Close, "close")
ch <- col.smb2RequestMetric(&smb2Calls.Flush, "flush")
ch <- col.smb2RequestMetric(&smb2Calls.Read, "read")
ch <- col.smb2RequestMetric(&smb2Calls.Write, "write")
ch <- col.smb2RequestMetric(&smb2Calls.Lock, "lock")
ch <- col.smb2RequestMetric(&smb2Calls.Ioctl, "ioctl")
ch <- col.smb2RequestMetric(&smb2Calls.Cancel, "cancel")
ch <- col.smb2RequestMetric(&smb2Calls.KeepAlive, "keepalive")
ch <- col.smb2RequestMetric(&smb2Calls.Find, "find")
ch <- col.smb2RequestMetric(&smb2Calls.Notify, "notify")
ch <- col.smb2RequestMetric(&smb2Calls.GetInfo, "getinfo")
ch <- col.smb2RequestMetric(&smb2Calls.SetInfo, "setinfo")
ch <- col.smb2RequestMetric(&smb2Calls.Break, "break")
}
sysCalls := smbProfileInfo.profileStatus.SystemCalls
if sysCalls != nil {
ch <- col.vfsIORequestMetric(&sysCalls.PRead, "pread")
ch <- col.vfsIORequestMetric(&sysCalls.AsysPRead, "asys_pread")
ch <- col.vfsIORequestMetric(&sysCalls.PWrite, "pwrite")
ch <- col.vfsIORequestMetric(&sysCalls.AsysPWrite, "asys_pwrite")
ch <- col.vfsIORequestMetric(&sysCalls.AsysFSync, "asys_fsync")
ch <- col.vfsRequestMetric(&sysCalls.Opendir, "opendir")
ch <- col.vfsRequestMetric(&sysCalls.FDOpendir, "fdopendir")
ch <- col.vfsRequestMetric(&sysCalls.Readdir, "readdir")
ch <- col.vfsRequestMetric(&sysCalls.Rewinddir, "rewinddir")
ch <- col.vfsRequestMetric(&sysCalls.Mkdirat, "mkdirat")
ch <- col.vfsRequestMetric(&sysCalls.Closedir, "closedir")
ch <- col.vfsRequestMetric(&sysCalls.Open, "open")
ch <- col.vfsRequestMetric(&sysCalls.OpenAt, "openat")
ch <- col.vfsRequestMetric(&sysCalls.CreateFile, "createfile")
ch <- col.vfsRequestMetric(&sysCalls.Close, "close")
ch <- col.vfsRequestMetric(&sysCalls.Lseek, "lseek")
ch <- col.vfsRequestMetric(&sysCalls.RenameAt, "renameat")
ch <- col.vfsRequestMetric(&sysCalls.Stat, "stat")
ch <- col.vfsRequestMetric(&sysCalls.FStat, "fstat")
ch <- col.vfsRequestMetric(&sysCalls.LStat, "lstat")
ch <- col.vfsRequestMetric(&sysCalls.FStatAt, "fstatat")
ch <- col.vfsRequestMetric(&sysCalls.UnlinkAt, "unlinkat")
ch <- col.vfsRequestMetric(&sysCalls.Chmod, "chmod")
ch <- col.vfsRequestMetric(&sysCalls.FChmod, "fchmod")
ch <- col.vfsRequestMetric(&sysCalls.FChown, "fchown")
ch <- col.vfsRequestMetric(&sysCalls.LChown, "lchown")
ch <- col.vfsRequestMetric(&sysCalls.Chdir, "chdir")
ch <- col.vfsRequestMetric(&sysCalls.GetWD, "getwd")
ch <- col.vfsRequestMetric(&sysCalls.Fntimes, "fntimes")
ch <- col.vfsRequestMetric(&sysCalls.FTruncate, "ftruncate")
ch <- col.vfsRequestMetric(&sysCalls.FAllocate, "fallocate")
ch <- col.vfsRequestMetric(&sysCalls.ReadLinkAt, "readlinkat")
ch <- col.vfsRequestMetric(&sysCalls.SymLinkAt, "symlinkat")
ch <- col.vfsRequestMetric(&sysCalls.LinkAt, "linkat")
ch <- col.vfsRequestMetric(&sysCalls.MknodAt, "mknodat")
ch <- col.vfsRequestMetric(&sysCalls.RealPath, "realpath")
}
}

Expand Down
23 changes: 17 additions & 6 deletions internal/metrics/smbinfo.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,34 +2,42 @@

package metrics

import (
"github.com/go-logr/logr"
)

// SMBInfo provides a bridge layer between raw smbstatus info and exported
// metric counters. It also implements the more complex logic which requires in
// memory re-mapping of the low-level information (e.g., stats by machine/user).
type SMBInfo struct {
tconsStatus *SMBStatus
sessionsStatus *SMBStatus
log logr.Logger
}

func NewSMBInfo() *SMBInfo {
func NewSMBInfo(log logr.Logger) *SMBInfo {
return &SMBInfo{
tconsStatus: NewSMBStatus(),
sessionsStatus: NewSMBStatus(),
log: log,
}
}

func NewUpdatedSMBInfo() (*SMBInfo, error) {
smbinfo := NewSMBInfo()
func NewUpdatedSMBInfo(log logr.Logger) (*SMBInfo, error) {
smbinfo := NewSMBInfo(log)
err := smbinfo.Update()
return smbinfo, err
}

func (smbinfo *SMBInfo) Update() error {
tconsStatus, err := RunSMBStatusShares()
if err != nil {
smbinfo.log.Error(err, "smbsstatus --shares failed")
return err
}
sessionsStatus, err := RunSMBStatusProcesses()
if err != nil {
smbinfo.log.Error(err, "smbsstatus --processes failed")
return err
}
smbinfo.tconsStatus = tconsStatus
Expand Down Expand Up @@ -145,23 +153,26 @@ func isInternalServiceID(serviceID string) bool {
// exported metric counters.
type SMBProfileInfo struct {
profileStatus *SMBProfile
log logr.Logger
}

func NewSMBProfileInfo() *SMBProfileInfo {
func NewSMBProfileInfo(log logr.Logger) *SMBProfileInfo {
return &SMBProfileInfo{
profileStatus: NewSMBProfile(),
log: log,
}
}

func NewUpdatedSMBProfileInfo() (*SMBProfileInfo, error) {
smbProfileInfo := NewSMBProfileInfo()
func NewUpdatedSMBProfileInfo(log logr.Logger) (*SMBProfileInfo, error) {
smbProfileInfo := NewSMBProfileInfo(log)
err := smbProfileInfo.Update()
return smbProfileInfo, err
}

func (smbProfileInfo *SMBProfileInfo) Update() error {
profiuleStatus, err := RunSMBStatusProfile()
if err != nil {
smbProfileInfo.log.Error(err, "smbsstatus --profile failed")
return err
}
smbProfileInfo.profileStatus = profiuleStatus
Expand Down
12 changes: 6 additions & 6 deletions internal/metrics/smbstatus.go
Original file line number Diff line number Diff line change
Expand Up @@ -259,12 +259,12 @@ type SMBProfileSMB2Calls struct {

// SMBProfile represents (a subset of the) output of 'smbstatus --profile'
type SMBProfile struct {
Timestamp string `json:"timestamp"`
Version string `json:"version"`
SmbConf string `json:"smb_conf"`
SmbdLoop SMBProfileLoop `json:"SMBD loop"`
SystemCalls SMBProfileSyscalls `json:"System Calls"`
SMB2Calls SMBProfileSMB2Calls `json:"SMB2 Calls"`
Timestamp string `json:"timestamp"`
Version string `json:"version"`
SmbConf string `json:"smb_conf"`
SmbdLoop *SMBProfileLoop `json:"SMBD loop"`
SystemCalls *SMBProfileSyscalls `json:"System Calls"`
SMB2Calls *SMBProfileSMB2Calls `json:"SMB2 Calls"`
}

// LocateSMBStatus finds the local executable of 'smbstatus' on host.
Expand Down
15 changes: 15 additions & 0 deletions internal/metrics/smbstatus_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1772,6 +1772,13 @@ var (
}
}
`

smbstatusProfileOutput8 = `
{
"timestamp":"2024-12-23T12:38:58.644260+0200",
"version":"4.22.0pre1-GIT-bc45829f56c",
"smb_conf":"//etc/samba/smb.conf"
}`
)

//revive:enable line-length-limit
Expand Down Expand Up @@ -1880,3 +1887,11 @@ func TestParseSMBStatusProfile(t *testing.T) {
assert.Equal(t, profile.SMB2Calls.Read.Outbytes, 10486240)
assert.Equal(t, profile.SMB2Calls.Write.Inbytes, 90180784)
}

func TestParseSMBStatusProfileNoData(t *testing.T) {
profile, err := parseSMBProfile(smbstatusProfileOutput8)
assert.NoError(t, err)
assert.Nil(t, profile.SmbdLoop)
assert.Nil(t, profile.SystemCalls)
assert.Nil(t, profile.SMB2Calls)
}