3535
3636import javax .annotation .PostConstruct ;
3737import javax .inject .Inject ;
38+ import java .util .ArrayList ;
39+ import java .util .List ;
40+ import java .util .Timer ;
41+ import java .util .TimerTask ;
42+ import java .util .concurrent .ConcurrentHashMap ;
3843import java .util .function .DoubleFunction ;
3944
4045public class Micrometer implements IStatCollector {
4146
47+ private static final int CACHE_UPDATE_INTERVAL = 20 * 1000 ; // update cache every 20 seconds
48+
4249 @ Inject
4350 private MeterRegistry registry ;
4451
@@ -50,6 +57,12 @@ public class Micrometer implements IStatCollector {
5057
5158 private final Logger logger = LogManager .getLogger (getClass ());
5259
60+ // keeps track of the number of proxies per spec id
61+ private final ConcurrentHashMap <String , Integer > proxyCountCache = new ConcurrentHashMap <>();
62+
63+ // need to store a reference to the proxyCounters as the Micrometer library only stores weak references
64+ private final List <ProxyCounter > proxyCounters = new ArrayList <>();
65+
5366 private Counter appStartFailedCounter ;
5467
5568 private Counter authFailedCounter ;
@@ -58,8 +71,6 @@ public class Micrometer implements IStatCollector {
5871
5972 private Counter userLogouts ;
6073
61- private Number usersLoggedIn ;
62-
6374 @ PostConstruct
6475 public void init () {
6576
@@ -72,9 +83,19 @@ public void init() {
7283 for (ProxySpec spec : proxyService .getProxySpecs (null , true )) {
7384 registry .counter ("appStarts" , "spec.id" , spec .getId ());
7485 registry .counter ("appStops" , "spec.id" , spec .getId ());
86+ ProxyCounter proxyCounter = new ProxyCounter (spec .getId ());
87+ proxyCounters .add (proxyCounter );
88+ registry .gauge ("shinyproxy_absolute_apps_running" , Tags .of ("spec.id" , spec .getId ()), proxyCounter , ProxyCounter ::getProxyCount );
7589 registry .timer ("startupTime" , "spec.id" , spec .getId ());
7690 registry .timer ("usageTime" , "spec.id" , spec .getId ());
7791 }
92+
93+ new Timer ().schedule (new TimerTask () {
94+ @ Override
95+ public void run () {
96+ updateCachedProxyCount ();
97+ }
98+ }, 0 , CACHE_UPDATE_INTERVAL );
7899 }
79100
80101 @ EventListener
@@ -115,4 +136,32 @@ public void onAuthFailedEvent(AuthFailedEvent event) {
115136 authFailedCounter .increment ();
116137 }
117138
139+ /**
140+ * Updates the cache containing the number of proxies running for each spec id.
141+ * We only update this value every CACHE_UPDATE_INTERVAL because this is a relative heavy computation to do.
142+ * Therefore we don't want that this calculation is performed every time the guage is updated.
143+ * Especially since could be called using an HTTP request.
144+ */
145+ private void updateCachedProxyCount () {
146+ for (ProxySpec spec : proxyService .getProxySpecs (null , true )) {
147+ Integer count = proxyService .getProxies (p -> p .getSpec ().getId ().equals (spec .getId ()), true ).size ();
148+ proxyCountCache .put (spec .getId (), count );
149+ logger .debug (String .format ("Running proxies count for spec %s: %s " , spec .getId (), count ));
150+ }
151+ }
152+
153+ private class ProxyCounter {
154+
155+ private final String specId ;
156+
157+ public ProxyCounter (String specId ) {
158+ this .specId = specId ;
159+ }
160+
161+ public int getProxyCount () {
162+ return proxyCountCache .getOrDefault (specId , null );
163+ }
164+
165+ }
166+
118167}
0 commit comments