Writing a gemini statistics program in fishscript



As a member of Ctrl-C Club tilde community I enjoy many benefits including the hosting of this gemlog.

All Ctrl-C Club user gemlogs

As of today Ctrl-C Club hosts 70 members' gemlogs.

In my last post I criticized the productivity trap of self-logging one's daily hours how your spend your time, especially as it comes to coding.

Why Self Track?

In an earlier post I railed against the burgeoning use of 'liking' on a few capsules. Thankfully, that practice seems to have died out; maybe my post helped convince people? No idea.

Likes on Gemini? NO!

And here is your hypocrite again this time writing up about the gemlog statistics reporting program I wrote in fishscript, the language of fish shell, which I use as my shell on my personal laptop. It's also our standard shell when you log into Ctrl-C Club.

Here's the script: It's about 30 lines of code without comments, 50 with.

Gemstats.fish on Tildegit

So after all this huffing and puffing about liking and logging as narcissistic and fixated on measuring things that would be better left unmeasured here I am publishing something that helps one identify the total number of readers of their gemlog.

From running this script today I can see:

Gemlog stats for Ctrl-C Club
Views today:  280
Views past month:  37151
Views for all time:  157432

Gemlog stats for ~lettuce
Views today:  71
Views past month:  4341
Views for all time:  18041

Maybe a better script would just be one that reports at least 1 person read my gemlog. It would just check to see one's had at least one reader for the past month or year or of all time. If that number is greater than 1 it can just report back a confirmation that yes, you've had readers. This would replace lines 40 - 48 in my program, that currently report the above statistics.

if math $user_subtotal + $user_subtotal2 > 0
  echo "Congratulations, you have some readers."

Fish Scripting

Ok, let's get to the script.

Fish's goals as a scripting language and shell is to be much easier to use than Bash. I'll push back that even though it is much easier, it still causes me plenty of time looking up how to do things, but the documentation is mostly clear and easy to read.

Fish shell docs on the web

Unlike Bash the command 'set' is used to create a variable in fishscript. Like in Bash, putting a dollar sign is how we get the value of a variable. We start by creating a variable access_log and storing the location of a temporary copy of the gemini server access logs.

set access_log ~/.temp.log
cat "/home/gemini/access.log" > $access_log

Then we store the current day, month, year, which we can find using the date Linux program.

set day (date +"%d")
set month (date +"%m")
set year (date +"%Y")

Now we want to find out the number of the previous month, and whether it's the same year. Basically, if we're in January, we'll need to manually say the previous month was month 12 of the previous year, and if so the year of that month was 1 less than the current year. Otherwise the month is one less than now and the same year. All those p variables below stand for previous.

if test $month -eq 1 
 # check whether current month is jan
 set pmonth 12 #set to dec
 set pyear (math (date +"%Y") - 1) #set to previous year
 set pmonth (math $month - 1) #set to prev month
 set pyear $year

Next we need to find out how many days are in the previous month so we can be use to loop through and check the stats for each days in the month in the previous month that we want to check. I thought I could use a special 'cal' command, but it's not installed on the server. So with some brainstorming I created a list (array, in fish) holding the total number of days for each month. Yes, I sang '30 days has september, april, june and november...' in my head to figure this out. Fish's lists begin their index with 1 instead of 0, like Lua. I am not accounting for leapyear.

#              J   F M  A  M  J  J  A  S  O  N  D
set month_days 31 28 31 30 31 30 31 31 30 31 30 31
set total_days_prev_month $month_days[$pmonth]

If today is the 17th and I want stats for the past 30 days then I'll want to loop from the 17th of the previous month to the last day of that month. Then I'll want to add in stats for the current month. I do this both for the current $USER running the script as well as for the entire tilde server. I'm making extensive use of grep to read through each line of the file and counting the number of lines that match. This part was like a little puzzle to master the date command, like doing code-Sudoku.

for day_counter in (seq $day $total_days_prev_month)
    set user_subtotal (grep $USER $access_log | grep (date --date=$pyear-$pmonth-$day_counter +"%Y-%m-%d" ) | wc -l)
    set entire_subtotal (grep (date --date=$pyear-$pmonth-$day_counter +"%Y-%m-%d" ) $access_log | wc -l)

set user_subtotal2 (grep $USER $access_log | grep (date +"%m") | wc -l)
set entire_subtotal2 ( grep (date +"%m") $access_log | wc -l)

Ok we've totaled up the total views for the server and an individual user for past month. Then I print it all out and delete the temporary log file afterwards. Basically, for the entire server I just count the total number of lines, since each line is a report of someone accessing any of our gemlogs. I run a similar line for viewing an individual's total number of viewers but filtering it so it only counts if a user's name is in there (having been accessed). For finding out total viewers today I pass in a search for today's date as well.

echo "Gemlog stats for Ctrl-C Club"
echo "Views today: " ( grep (date +"%Y-%m-%d") $access_log | wc -l )
echo "Views past month: " (math $entire_subtotal + $entire_subtotal2)
echo "Views for all time: " (cat $access_log | wc -l) # just the total number of lines of the log
echo -e "\nGemlog stats for ~$USER"
echo "Views today: " (grep $USER $access_log | grep (date +"%Y-%m-%d") | wc -l)
echo "Views past month: " (math $user_subtotal + $user_subtotal2)
echo "Views for all time: " (grep $USER $access_log | wc -l)
rm $access_log


So this took me some time to surf around the fish shell documentation but ultimately it wasn't too bad.

And that's how you script a fish.