1+ import calendar
2+ import csv
3+ from datetime import datetime , timedelta , timezone
4+ from pathlib import Path
15from typing import Annotated , Optional
26
7+ import requests
8+ import typer
39from rich import progress
4- from rich .table import Table
510from rich .live import Live
6- from deployer .cli_app import generate_app
7- import typer
8- import csv
9- import calendar
10- import requests
11- from pathlib import Path
12- from datetime import datetime , timedelta , timezone
11+ from rich .table import Table
1312from yarl import URL
13+
14+ from deployer .cli_app import generate_app
1415from deployer .infra_components .cluster import Cluster
1516
1617# Usernames to ignore when calculating MAU
17- USERNAMES_TO_IGNORE = set ([
18+ USERNAMES_TO_IGNORE = {
1819 "deployment-service-check" ,
19-
2020 # 2i2c staff GitHub IDs
2121 "agoose77" ,
2222 "choldgraf" ,
2727 "jnywong" ,
2828 "yuvipanda" ,
2929 "jmunroe" ,
30-
3130 # 2i2c staff google ids
3231 "ahollands@2i2c.org" ,
3332 "choldgraf@2i2c.org" ,
3736 "hcampbell@2i2c.org" ,
3837 "jwong@2i2c.org" ,
3938 "yuvipanda@2i2c.org" ,
40- "jmunroe@2i2c.org"
41- ])
39+ "jmunroe@2i2c.org" ,
40+ }
41+
4242
4343@generate_app .command ()
4444def mau (
4545 month : str = typer .Argument (help = "Month to generate MAU data for" ),
46- cluster_name : Optional [str ] = typer .Option (None , help = "Restrict to just one cluster" ),
47- csv_file : Annotated [Path | None , typer .Option (help = "Output data to csv file at this path" )] = None
46+ cluster_name : Optional [str ] = typer .Option (
47+ None , help = "Restrict to just one cluster"
48+ ),
49+ csv_file : Annotated [
50+ Path | None , typer .Option (help = "Output data to csv file at this path" )
51+ ] = None ,
4852):
4953 """
5054 Generate MAU for all (or some) clusters for a given month
@@ -67,13 +71,21 @@ def mau(
6771 dates_progress = progress_bar .add_task ("Days" )
6872
6973 for cluster in clusters :
70- progress_bar .update (clusters_progress , description = f"Processing { cluster .spec ['name' ]} " , advance = 1 )
71- promql_api = URL (f"{ cluster .get_external_prometheus_url ()} /api/v1/query_range" )
74+ progress_bar .update (
75+ clusters_progress ,
76+ description = f"Processing { cluster .spec ['name' ]} " ,
77+ advance = 1 ,
78+ )
79+ promql_api = URL (
80+ f"{ cluster .get_external_prometheus_url ()} /api/v1/query_range"
81+ )
7282
7383 time_parts = month .split ("-" , 2 )
7484
7585 # Explicitly construct the datetime as UTC, so we get standardized MAU for all our clusters
76- start_date = datetime (int (time_parts [0 ]), int (time_parts [1 ]), 1 , tzinfo = timezone .utc )
86+ start_date = datetime (
87+ int (time_parts [0 ]), int (time_parts [1 ]), 1 , tzinfo = timezone .utc
88+ )
7789
7890 # Get all pods that start with jupyter-.*, and treat them as user servers.
7991 # We could join with kube_pod_labels for a more accurate version of this.
@@ -98,12 +110,16 @@ def mau(
98110 start_time = start_date + timedelta (days = i )
99111 end_time = start_time + timedelta (days = 1 ) - timedelta (seconds = 1 )
100112
101- progress_bar .update (dates_progress , completed = i , description = f"Processing { start_time .strftime ('%Y-%m-%d' )} " )
113+ progress_bar .update (
114+ dates_progress ,
115+ completed = i ,
116+ description = f"Processing { start_time .strftime ('%Y-%m-%d' )} " ,
117+ )
102118 params = {
103119 "query" : query ,
104120 "start" : int (start_time .timestamp ()),
105121 "end" : int (end_time .timestamp ()),
106- "step" : "1m"
122+ "step" : "1m" ,
107123 }
108124
109125 query_api = promql_api .with_query (params )
@@ -113,16 +129,18 @@ def mau(
113129
114130 result = resp .json ()["data" ]["result" ]
115131 for row in result :
116- username = row [' metric' ][ ' annotation_hub_jupyter_org_username' ]
132+ username = row [" metric" ][ " annotation_hub_jupyter_org_username" ]
117133
118134 if username in USERNAMES_TO_IGNORE :
119135 continue
120136
121137 # Since "step" is 1m, each value that is present indicates this pod was present
122138 # for that minute. So the total number of values present indicates how long the
123139 # user was active.
124- minutes_active = len (row ['values' ])
125- user_activity [username ] = user_activity .get (username , 0 ) + minutes_active
140+ minutes_active = len (row ["values" ])
141+ user_activity [username ] = (
142+ user_activity .get (username , 0 ) + minutes_active
143+ )
126144 cluster_activity [cluster .spec ["name" ]] = len (user_activity )
127145
128146 table .add_row (cluster .spec ["name" ], str (len (user_activity )))
@@ -132,4 +150,4 @@ def mau(
132150 writer = csv .writer (f )
133151 writer .writerow (("cluster_name" , "mau" ))
134152 for name , active_users in cluster_activity .items ():
135- writer .writerow ((name , str (active_users )))
153+ writer .writerow ((name , str (active_users )))
0 commit comments