Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fetch plugin logs from server #193

Merged
merged 10 commits into from
Jan 30, 2024
Merged

Fetch plugin logs from server #193

merged 10 commits into from
Jan 30, 2024

Conversation

hanzei
Copy link
Contributor

@hanzei hanzei commented Dec 18, 2023

Summary

To make it easier for plugin developers to get the log of the plugin that they are developing, this PR add two new Make target:

  • make logs fetches the latest 500 log messages from the MM server. This is useful for figuring out existing issues with the plugin. I'm 0/5 of the concrete numbers. Maybe the command should show the latest 100 messages from the plugin instead of filtering 500 general ones.
  • make logs-watch is the development-focused target. It continually fetches logs from Mattermost and prints only new ones to stdout. It's meant to be run in a separate terminal while developing the plugin.
Screencast.from.18.12.2023.12.37.35.webm

Ticket Link

NONE

@hanzei hanzei added the 2: Dev Review Requires review by a core committer label Dec 18, 2023
Comment on lines +84 to +87
if allNew != tc.expectedAllNew {
t.Logf("expected allNew: %v, got %v", tc.expectedAllNew, allNew)
t.Fail()
}
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I really wanted to around importing testify as that way all plugins would have it in their go.mod.

@@ -1,6 +1,6 @@
module github.com/mattermost/mattermost-plugin-starter-template

go 1.19
go 1.21
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For slices import

now := time.Now()
var oldest string

ticker := time.NewTicker(1 * time.Second)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fetching the logs every second feels good from a UX perspective. I think the load is acceptable, but I'm open to increasing the interval.

It could even go down to 500 milliseconds, at least for local dev environments.

@hanzei
Copy link
Contributor Author

hanzei commented Dec 19, 2023

I've been thinking about adding a mmctl logs watch command. If we want to do that, where would be shared code life?

Copy link
Member

@lieut-data lieut-data left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is cool, @hanzei! Love the simplicity that this affords plugin developers. A few thoughts below.

build/pluginctl/logs.go Outdated Show resolved Hide resolved
build/pluginctl/logs.go Outdated Show resolved Hide resolved
build/pluginctl/logs.go Outdated Show resolved Hide resolved
build/pluginctl/logs.go Outdated Show resolved Hide resolved
build/pluginctl/logs.go Outdated Show resolved Hide resolved
// fetchLogs fetches log entries from Mattermost
// and filters them based on pluginID and timestamp.
func fetchLogs(ctx context.Context, client *model.Client4, page int, pluginID string, since time.Time) ([]string, error) {
logs, _, err := client.GetLogs(ctx, page, logsPerPage)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not required for this PR, but I wonder if we can do better than just polling a logs endpoint that may not give us all the logs if a high volume of logs gets emitted? (e.g. 101 new log lines between polling intervals means some logs get "lost").

When I develop and want plugin logs, I basically just tail -f | jq ... the log file. Could we do something as reliable as that?

Copy link
Contributor Author

@hanzei hanzei Jan 4, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Regarding the high volume of logs, please see #193 (comment). The code does now fetch more than one page.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When I develop and want plugin logs, I basically just tail -f | jq ... the log file. Could we do something as reliable as that?

I would love to use this simple, reliable solution, but I wanted to build a tool that also works for remote servers like the ones in MM Cloud. Is there another similar tool that we can use here instead of reading the local file?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For MM Cloud, at least, I just use Grafana's livestreaming feature. Unless we build something more robust into the server, I guess we'll be limited in what we can do here, which might be fine for the level of logging needed.

build/pluginctl/logs.go Show resolved Hide resolved
Comment on lines 82 to 93
i := slices.Index(logs, oldest)
switch i {
case -1:
// Every log entry is new
return logs, logs[(len(logs) - 1)], true
case len(logs) - 1:
// No new log entries
return nil, oldest, false
default:
// Filter out oldest log entry
return logs[i+1:], logs[(len(logs) - 1)], false
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See discussion above about whether or not we can eliminate allNew, but if so, I think this whole block could be reduced to:

return logs[i+1:], logs[(len(logs) - 1]

The idea being that if i == -1, that's the same as returning logs[0:], and if i == len(logs) - 1, that's the same as returning logs[len(logs):] or the nil slice anyway.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That is a clever suggestion, even though I'm not sure if it is easier to read. I've simplified the return value via 91f7b12, but I'm leaning toward keeping the switch as it is. Let me know what you think!

build/pluginctl/logs.go Show resolved Hide resolved
@codecov-commenter
Copy link

codecov-commenter commented Jan 4, 2024

Codecov Report

All modified and coverable lines are covered by tests ✅

Comparison is base (eef27c8) 5.26% compared to head (cfb38d8) 5.26%.
Report is 3 commits behind head on master.

Additional details and impacted files
@@          Coverage Diff           @@
##           master    #193   +/-   ##
======================================
  Coverage    5.26%   5.26%           
======================================
  Files           3       3           
  Lines          38      38           
======================================
  Hits            2       2           
  Misses         36      36           

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

Copy link
Member

@mickmister mickmister left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, @hanzei do you have any remaining major concerns?

build/pluginctl/logs_test.go Outdated Show resolved Hide resolved
@hanzei
Copy link
Contributor Author

hanzei commented Jan 5, 2024

LGTM, @hanzei do you have any remaining major concerns?

@mickmister I think you meant to ping @lieut-data, right?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
4: Reviews Complete All reviewers have approved the pull request
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants