Inactive users reporting

Here is a bit of a further dive into the command that @ahmaddanial provided, with some additions.

The mattermost instance uses Epoch time to store time values, and in the Status table I have found that the user ID as well as the Epoch timestamp of their last activity are contained.

Utilizing the SQL CLI command as follows, you can write all UserId and LastActivityAt values to a file, for further analysis as explained further in this post.

SELECT UserId,LastActivityAt FROM Status INTO OUTFILE '/tmp/test4.csv' FIELDS TERMINATED BY ','  LINES TERMINATED BY '\n';

In the command above, you are outputting the contents of the two aforementioned tables into the file /tmp/test4.csv, where each row queried from the database contains the User ID as well as the Epoch time formatted stamp of the last time they were active.
Here is an example of the output you should expect to see from your SQL query, as well as a sample of data from my own Mattermost Instance, which we will be working with a bit later in this post.

Query output:

Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 21
Server version: 8.0.22 MySQL Community Server - GPL

Copyright (c) 2000, 2020, Oracle and/or its affiliates. All rights reserved.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql> use mattermost;
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A

Database changed
mysql> SELECT UserId,LastActivityAt FROM Status INTO OUTFILE '/tmp/output.csv' FIELDS TERMINATED BY ','  LINES TERMINATED BY '\n';
Query OK, 43 rows affected (0.00 sec)

mysql>

And now for the information which was written to the file:

14mntogm5ff67jp75j15p1qnnr,1601015368224
1t8eejqpm3gkxr95o51y7zqweo,1600805793921
433r8gsyffrepczprymek6ecky,1605988064332
45exxzp9dj8hpgp65feqwii54a,1601850386879
4zt4bykmt7gqdyizmmmmeftjme,1603373266208
5nxnfcrtpfdf5fsjznmbrzdc1e,1603122003488
79kzmd6ds78gjmujnkfzmqtb8h,1605473281051
8gigbncfft8htn8aoyosyiem9w,1605645891797
8sg9cqztxjngdnbbbwhw643eae,1601256715987
95zjx1su7fyzjrbopxqz4ms1we,1600645344475
d9s6yrfpk3bfme8h1ad4zwgzia,1603869451323
deqoroxry3fj7c3acw6gtky6iw,1604026827343

So now we have the User ID’s and Epoch formatted timestamp of the time each user was last active.
At this point, your probably thinking “great, where is he going with this, I can’t even understand all those numbers, they make no sense,” and that’s alright, me too, seriously! :slight_smile:

Now we have a nice CSV file which is great for importing into Google Sheets!

Using a file transfer protocol such as SFTP or FTP, or simply copy/paste into a CSV file that is located on the machine you are going to open a new Google Spreadsheet on (if you have fewer user, I only have about 100, so it wasn’t a huge task to do)

Epoch Time is the amount of seconds since the Epoch, or the date 1970-01-01T00:00:00Z. Knowing this, lets import into our google sheet. At this point, as you continue to read this post, please refer to this demonstration spreadsheet that I have created, which can be accessed here.. This is going to be extremely helpful in explaining the concept without needing to take a large amount of screenshots, which is very time consuming, and I strongly recommend viewing this document.

Refer to Column D, and take note of the function indicated in orange at the top of the column. This function has been individually applied to each row in the column, and each of the columns, which is obviously a lot of work.

Lets take a look at the math of the function, where B2 equals 1601015368224
=B2/1000/60/60/24 + DATE(1970,1,1)
We want to end up converting the timestamp from the database into days since Epoch Zero.
We know that there are 1000 milliseconds in a second, so we first divide the value by 1000.
1601015368224/1000=1601015368.22
We now have the date the user was last active in seconds

Now, we convert to minutes. We know that there are 60 seconds in a minute, so we divide by 60:
1601015368.22 / 60=26683589.4703

Now that we have the number of minutes since the last time the user was active, we need to convert this number to hours, again, dividing by 60, as there are 60 minutes in an hour:
26683589.4703 / 60 =4 44726.491172

Now, we know there are 24 hours in a day, so we take the number of hours, and divide by 24:
444726.491172 / 24 = 18530.2704655

So, in the end of all this division, we know that the user was last active roughly 18530 days after Epoch Zero. But that still doesn’t answer our question, does it? We need to know what day is 18530 days after Epoch Zero. So lets do it!

This is the point where we’re all going to pause and be thankful for technology because my fingers are starting to ache quite a bit from typing for the last two hours doing research and writing this post :laughing: To sum it up, you add the number of days, which we just computed with math, to the date of Epoch Zero: 1970-01-01, which can easily be done in Google Sheets, in a function, as you can see referenced in the D1 Row. I used google to check my math, and sure enough, adding the number of days that we calculated here, to Epoch Zero, exactly matched the last active date!

(I tried to upload images it wouldn’t let me, I think my post is getting too long :slight_smile: )

Anyways, we’re at the point where we have a formula function that we know works, but who wants to copy and paste the same thing by hand every single time that you upload new data? Exactly, nobody!

That’s where the Google Sheets Array function comes in handy (reference row E1 in the google sheet)
Using this function, we simply specify the first and last row of the data we want to apply our function to, and the data between the start and end will all be processed as well!
As a result, you now have the UserID’s and human-formatted dates of last activity for your report, and can use conditional formatting to highlight all users not active before a specific date, therefore singling out specific inactive users! (See sheet two, called Final Output in which I have setup conditional formatting to show all users not active within the last month)

I hope this helps, and I’m thinking I’m going to develop a further plugin of some form that will do this automatically!

Please feel free to ask any additional questions or let me know what you would like to see in a plugin/integration, as I’m most certainly open to suggestions!

1 Like