diff --git a/go.mod b/go.mod index ca0fd77..4e62795 100644 --- a/go.mod +++ b/go.mod @@ -7,7 +7,7 @@ require ( github.com/go-kit/log v0.2.1 github.com/gorilla/mux v1.8.1 github.com/jmoiron/sqlx v1.3.5 - github.com/mattermost/mattermost/server/public v0.1.0 + github.com/mattermost/mattermost/server/public v0.1.1 github.com/mattermost/mattermost/server/v8 v8.0.0-20240326175929-75cf1f9d931a github.com/mattermost/squirrel v0.4.0 github.com/oklog/ulid v1.3.1 diff --git a/go.sum b/go.sum index a05325e..f8d0e92 100644 --- a/go.sum +++ b/go.sum @@ -352,8 +352,8 @@ github.com/mattermost/ldap v0.0.0-20231116144001-0f480c025956 h1:Y1Tu/swM31pVwwb github.com/mattermost/ldap v0.0.0-20231116144001-0f480c025956/go.mod h1:SRl30Lb7/QoYyohYeVBuqYvvmXSZJxZgiV3Zf6VbxjI= github.com/mattermost/logr/v2 v2.0.21 h1:CMHsP+nrbRlEC4g7BwOk1GAnMtHkniFhlSQPXy52be4= github.com/mattermost/logr/v2 v2.0.21/go.mod h1:kZkB/zqKL9e+RY5gB3vGpsyenC+TpuiOenjMkvJJbzc= -github.com/mattermost/mattermost/server/public v0.1.0 h1:64o/Ie8vXVNrgmBJxh9rFXbNQ+kV7+BQo/XT9u0GX8E= -github.com/mattermost/mattermost/server/public v0.1.0/go.mod h1:WeqCPudYLqk4HjjGvCMJwhtHMVvcNUTHIbrLmLjAD+4= +github.com/mattermost/mattermost/server/public v0.1.1 h1:T5UtZ0SB3rZvhiKFUxkPn4fNrEQTXAcmCHVkRct1dpk= +github.com/mattermost/mattermost/server/public v0.1.1/go.mod h1:WeqCPudYLqk4HjjGvCMJwhtHMVvcNUTHIbrLmLjAD+4= github.com/mattermost/mattermost/server/v8 v8.0.0-20240326175929-75cf1f9d931a h1:yPsYDtyoI98gzIPyAt7AxgtYqFq9qhp6oA1ss3O2hp8= github.com/mattermost/mattermost/server/v8 v8.0.0-20240326175929-75cf1f9d931a/go.mod h1:qQjPPGKiugHw6Tunlmq3cVDkKFFbgtMxIvyNJoN+p3Y= github.com/mattermost/squirrel v0.4.0 h1:azf9LZ+8JUTAvwt/njB1utkPqWQ6e7Rje2ya5N0P2i4= diff --git a/plugin.json b/plugin.json index 039c0dd..abe5a2d 100644 --- a/plugin.json +++ b/plugin.json @@ -6,7 +6,7 @@ "support_url": "https://github.com/mattermost/mattermost-plugin-metrics/issues", "release_notes_url": "https://github.com/mattermost/mattermost-plugin-metrics/releases/tag/v0.4.0", "icon_path": "assets/starter-template-icon.svg", - "version": "0.4.1", + "version": "0.5.0", "min_server_version": "6.3.0", "server": { "executables": { @@ -30,7 +30,7 @@ "display_name": "TSDB Path:", "type": "text", "help_text": "The local path where the time series database data is stored. Changing this setting requires a plugin restart.", - "default":"mattermost-plugin-metrics/data" + "default": "mattermost-plugin-metrics/data" }, { "key": "Dumps", @@ -38,5 +38,8 @@ "display_name": "Dump Table:" } ] + }, + "props": { + "support_packet": "Performance metrics" } } diff --git a/server/configuration.go b/server/configuration.go index cd1c35b..a31f253 100644 --- a/server/configuration.go +++ b/server/configuration.go @@ -39,18 +39,19 @@ type configuration struct { HonorTimestamps *bool // Option to enable the experimental in-memory metadata storage and append metadata to the WAL. EnableMetadataStorage *bool - // Scrape interval is the time between polling the /metrics endpoint + // Scrape interval is the time between polling the /metrics endpoint. ScrapeIntervalSeconds *int - // Screpe timeout tells scraper to give up on the poll for a single scrape attempt + // Screpe timeout tells scraper to give up on the poll for a single scrape attempt. ScrapeTimeoutSeconds *int - // RetentionDurationDays defines the retention time for the tsdb blocks + // RetentionDurationDays defines the retention time for the tsdb blocks. RetentionDurationDays *int - // FileStoreSyncPeriodMinutes is the period to sync local store with the remote filestore + // FileStoreSyncPeriodMinutes is the period to sync local store with the remote filestore. FileStoreSyncPeriodMinutes *int - // FileStoreCleanupPeriodMinutes is the period to run cleanup job in the filestore + // FileStoreCleanupPeriodMinutes is the period to run cleanup job in the filestore. FileStoreCleanupPeriodMinutes *int - // CollectMetricsFrom is the period to collect metrics to create the dump - CollectMetricsFrom *string `json:"collectmetricsfrom"` + // SupportPacketMetricsDays is the period to collect metrics to create the dump for the + // support packet. + SupportPacketMetricsDays *int `json:"supportpacketmetricsdays"` } func (c *configuration) SetDefaults() { @@ -93,8 +94,8 @@ func (c *configuration) SetDefaults() { if c.FileStoreCleanupPeriodMinutes == nil { c.FileStoreCleanupPeriodMinutes = model.NewInt(120) } - if c.CollectMetricsFrom == nil { - c.CollectMetricsFrom = model.NewString("3_days") + if c.SupportPacketMetricsDays == nil { + c.SupportPacketMetricsDays = model.NewInt(1) } } @@ -108,6 +109,9 @@ func (c *configuration) IsValid() error { if *c.BodySizeLimitBytes < 100 { return errors.New("openmetrics body size is not realistic, should be greater than 100 bytes") } + if *c.SupportPacketMetricsDays < 1 { + return errors.New("at least one day of metrics should be included to the support packet") + } return nil } diff --git a/server/support_packet.go b/server/support_packet.go new file mode 100644 index 0000000..e81052d --- /dev/null +++ b/server/support_packet.go @@ -0,0 +1,59 @@ +package main + +import ( + "context" + "errors" + "fmt" + "io" + "path/filepath" + "sort" + + "github.com/mattermost/mattermost/server/public/model" + "github.com/mattermost/mattermost/server/public/plugin" +) + +func (p *Plugin) GenerateSupportData(_ *plugin.Context) ([]*model.FileData, error) { + jobs, err := p.GetAllJobs(context.TODO()) + if err != nil { + return nil, fmt.Errorf("could not retrieve jobs") + } + + jobSlice := make([]*DumpJob, 0, len(jobs)) + for _, job := range jobs { + jobSlice = append(jobSlice, job) + } + + sort.Slice(jobSlice, func(i, j int) bool { + return jobSlice[i].CreateAt > jobSlice[j].CreateAt + }) + + var recentJob *DumpJob + for _, j := range jobSlice { + if j.Status == model.JobStatusSuccess { + recentJob = j + break + } + } + + if recentJob == nil { + return nil, errors.New("there is no dumps in the filestore, please create a tsdb dump first") + } + dumpLocation := recentJob.DumpLocation + + fr, err := p.fileBackend.Reader(dumpLocation) + if err != nil { + return nil, fmt.Errorf("could not read dump: %w", err) + } + defer fr.Close() + + b, err := io.ReadAll(fr) + if err != nil { + return nil, fmt.Errorf("could not read dump file into byte slice: %w", err) + } + + return []*model.FileData{{ + Filename: filepath.Base(dumpLocation), + Body: b, + }, + }, nil +}