litestack 0.2.6 → 0.4.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (46) hide show
  1. checksums.yaml +4 -4
  2. data/BENCHMARKS.md +11 -0
  3. data/CHANGELOG.md +19 -0
  4. data/Gemfile +2 -0
  5. data/README.md +1 -1
  6. data/assets/event_page.png +0 -0
  7. data/assets/index_page.png +0 -0
  8. data/assets/topic_page.png +0 -0
  9. data/bench/bench_jobs_rails.rb +1 -1
  10. data/bench/bench_jobs_raw.rb +1 -1
  11. data/bench/uljob.rb +1 -1
  12. data/lib/action_cable/subscription_adapter/litecable.rb +1 -11
  13. data/lib/active_support/cache/litecache.rb +1 -1
  14. data/lib/generators/litestack/install/templates/database.yml +5 -1
  15. data/lib/litestack/liteboard/liteboard.rb +172 -35
  16. data/lib/litestack/liteboard/views/index.erb +52 -20
  17. data/lib/litestack/liteboard/views/layout.erb +189 -38
  18. data/lib/litestack/liteboard/views/litecable.erb +118 -0
  19. data/lib/litestack/liteboard/views/litecache.erb +144 -0
  20. data/lib/litestack/liteboard/views/litedb.erb +168 -0
  21. data/lib/litestack/liteboard/views/litejob.erb +151 -0
  22. data/lib/litestack/litecable.rb +27 -37
  23. data/lib/litestack/litecable.sql.yml +1 -1
  24. data/lib/litestack/litecache.rb +7 -18
  25. data/lib/litestack/litedb.rb +17 -2
  26. data/lib/litestack/litejob.rb +2 -3
  27. data/lib/litestack/litejobqueue.rb +51 -48
  28. data/lib/litestack/litemetric.rb +46 -69
  29. data/lib/litestack/litemetric.sql.yml +14 -12
  30. data/lib/litestack/litemetric_collector.sql.yml +4 -4
  31. data/lib/litestack/litequeue.rb +9 -20
  32. data/lib/litestack/litescheduler.rb +84 -0
  33. data/lib/litestack/litesearch/index.rb +230 -0
  34. data/lib/litestack/litesearch/model.rb +178 -0
  35. data/lib/litestack/litesearch/schema.rb +193 -0
  36. data/lib/litestack/litesearch/schema_adapters/backed_adapter.rb +147 -0
  37. data/lib/litestack/litesearch/schema_adapters/basic_adapter.rb +128 -0
  38. data/lib/litestack/litesearch/schema_adapters/contentless_adapter.rb +17 -0
  39. data/lib/litestack/litesearch/schema_adapters/standalone_adapter.rb +33 -0
  40. data/lib/litestack/litesearch/schema_adapters.rb +9 -0
  41. data/lib/litestack/litesearch.rb +37 -0
  42. data/lib/litestack/litesupport.rb +55 -125
  43. data/lib/litestack/version.rb +1 -1
  44. data/lib/litestack.rb +2 -1
  45. data/lib/sequel/adapters/litedb.rb +3 -2
  46. metadata +20 -3
@@ -15,17 +15,17 @@
15
15
  h1 { font-family: antonio }
16
16
  #content{ padding-right: 12px; padding-left: 12px; padding-bottom: 60px;}
17
17
  table.head { margin-top: 12px; margin-bottom:12px}
18
- table.head select { color: #078; background-color: #fff; font-weight: normal }
18
+ select { color: #078; background-color: #fff; font-weight: normal }
19
19
  .table th { color: #078; font-weight: normal; }
20
20
  .table th.sorted { font-weight: bold }
21
21
  .table td { color: #444; vertical-align:middle; font-size: 18px}
22
22
  .table td:first-child { color: #444; vertical-align:middle; font-size: 15px; font-weight:normal}
23
23
  .table td.empty { text-align:center}
24
- a { color: #078; }
24
+ a, a.nav-link { color: #078; }
25
+ .nav-pills .nav-link.active { color: #fff; background-color: #078}
25
26
  a .logo { color: #000;}
26
27
  a:visited { color: #078; }
27
- //table.summary { width: 50% }
28
- span.hidden { display: none}
28
+ .hidden { display: none}
29
29
  div#search {margin-bottom: 8px}
30
30
  div#footer {position:fixed; left:0px; height: 40px; width:100%; background-color:#0891; border-top: #0893 1px solid; padding: 8px; bottom: 0; text-align: right}
31
31
  .logo{font-family: antonio}
@@ -41,23 +41,46 @@
41
41
  <div id="header">
42
42
  <h1><span class="logo"><span class="logo-half">lite</span>board | </span> <span class="logo smaller">the <span class="logo-half">lite</span>metric dashboard</span></span></h1>
43
43
  </div>
44
- <table class="head">
45
- <tr>
46
- <td>
47
- Showing data for the last <select onchange="window.location = locationWithParam('res', this.value)">
44
+ <div class="container">
45
+ <div class = "row">
46
+ &nbsp;<br/>
47
+ </div>
48
+ <div class="row">
49
+ <div class="col">
50
+ <nav class="navbar bg-body-tertiary">
51
+ <div>&nbsp;&nbsp;Showing data for the last <select onchange="window.location = locationWithParam('res', this.value)">
48
52
  <%= mapping = {'hour' => '60 minutes', 'day' => '24 hours', 'week' => '7 days', 'year' => '52 weeks'}%>
49
53
  <% ['hour', 'day', 'week', 'year'].each do |res| %>
50
54
  <option value=<%=res%> <%='selected' if res == @res%>><%=mapping[res]%></option>
51
55
  <% end %>
52
- </select>
53
- </td>
54
- <td></td>
55
- </tr>
56
- <tr>
57
- <td></td><td></td>
58
- </tr>
59
- </table>
56
+ </select></div>
57
+ </nav>
58
+ </div>
59
+ </div>
60
+ <div class = "row">
61
+ &nbsp;<br/>
62
+ </div>
60
63
  <%= yield %>
64
+
65
+ </div>
66
+
67
+ <div class="container" style="position: fixed; left:0px; top: 145px">
68
+ <div class="row justify-content-center">
69
+ <div class="col">
70
+ <div class="card" style="width: 15rem;">
71
+ <div class="card-body">
72
+ <ul class="nav nav-pills nav-fill flex-column list-group list-group-flush">
73
+ <li class="list-group-item"><a class="nav-link <%='active' unless @topic%>" href="<%=index_url%>">Home</a></li>
74
+ <%@topics.each do |topic|%>
75
+ <li class="list-group-item"><a class="nav-link <%='active' if @topic == topic[0]%>" href="<%=topic_url(topic[0])%>"><%=topic[0]%></a></li>
76
+ <%end%>
77
+ </ul>
78
+ </div>
79
+ </div>
80
+ </div>
81
+ </div>
82
+ </div>
83
+
61
84
  </div>
62
85
  <div id="footer">
63
86
  Powered by <a href="https://www.github.com/oldmoe/litestack" target="_blank"><span class="logo"><span class="logo-half">lite</span>stack</span></a>
@@ -65,44 +88,170 @@
65
88
  <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js" integrity="sha384-geWF76RCwLtnZ8qwWowPQNguL3RmwHVBC9FhGdlKrxdiJJigb/j/68SIy3Te4Bkz" crossorigin="anonymous"></script>
66
89
  </body>
67
90
  <script>
68
- google.charts.load('current', {'packages':['corechart']});
91
+ google.charts.load('current', {'packages':['corechart', 'bar']});
69
92
 
70
- google.charts.setOnLoadCallback(drawChart);
93
+ google.charts.setOnLoadCallback(drawMiniColumnChart);
94
+ google.charts.setOnLoadCallback(drawColumnChart);
95
+ google.charts.setOnLoadCallback(drawPieChart);
96
+ google.charts.setOnLoadCallback(drawStackedColumnChart);
71
97
 
72
- function drawChart() {
98
+
99
+ function drawMiniColumnChart() {
100
+ elements = document.querySelectorAll(".inlineminicolumn")
101
+ elements.forEach(element => {
102
+ var label = element.dataset.label;
103
+ var mydata = eval(element.innerText)
104
+ element.innerText = ''
105
+ element.classList.remove("hidden")
106
+ if(mydata.length > 1) {
107
+ mydata.forEach(row => {
108
+ if(mydata[0].length == 5){ // we are doing custom tooltips
109
+ if(row[0] != "Time"){
110
+ row[1] = Number(row[1].toPrecision(4))
111
+ row[3] = Number(row[2].toPrecision(4))
112
+ row[2] = row[0]+': '+mydata[0][1]+' '+row[1]
113
+ row[4] = row[0]+': '+mydata[0][3]+' '+row[3]
114
+ }
115
+ }
116
+ })
117
+ var data = google.visualization.arrayToDataTable(
118
+ mydata
119
+ )
120
+ var options = {
121
+ animation: {'startup': true, 'duration': 300},
122
+ width: 300,
123
+ height: 70,
124
+ chartArea: {width:'100%', height: '100%'},
125
+ backgroundColor: 'none',
126
+ bar: {groupWidth: "61.8%"},
127
+ colors : ['#089', 'silver' ],
128
+ vAxis: {'gridlines': {'count' : 0}, 'textPosition' : 'none', 'baselineColor' : 'none'},
129
+ hAxis: { 'count' : 0, 'textPosition' : 'none', 'baselineColor' : 'none'},
130
+ legend: {'position': 'none'},
131
+ tooltip: {showColorCode: true, isHtml: true},
132
+ isStacked: true
133
+ }
134
+ var chart = new google.visualization.ColumnChart(element);
135
+ chart.draw(data, options);
136
+ }
137
+ })
138
+ }
139
+
140
+ function drawColumnChart() {
73
141
  elements = document.querySelectorAll(".inlinecolumn")
74
142
  elements.forEach(element => {
75
- //console.log(element)
76
143
  var label = element.dataset.label;
77
144
  var mydata = eval(element.innerText)
78
- //console.log(mydata)
79
- if(mydata.length > 0) {
80
- var data = new google.visualization.DataTable();
81
-
82
- data.addColumn('string', 'Time');
83
- data.addColumn('number', label);
145
+ element.innerText = ''
146
+ element.classList.remove("hidden")
147
+ if(mydata.length > 1) {
84
148
  mydata.forEach(row => {
85
- row[1] = Number(row[1])
86
- data.addRows([row])
149
+ if(mydata[0].length == 5){ // we are doing custom tooltips
150
+ if(row[0] != "Time"){
151
+ row[1] = Number(row[1].toPrecision(4))
152
+ row[3] = Number(row[2].toPrecision(4))
153
+ row[2] = row[0]+': '+mydata[0][1]+' '+row[1]
154
+ row[4] = row[0]+': '+mydata[0][3]+' '+row[3]
155
+ }
156
+ }
87
157
  })
88
- //data.addRows(mydata)
158
+ var data = google.visualization.arrayToDataTable(
159
+ mydata
160
+ )
89
161
  var options = {
90
162
  animation: {'startup': true, 'duration': 300},
91
- width: 400,
92
- height: 40,
163
+ width: 550,
164
+ height: 350,
165
+ chartArea: {width:'100%', height: '80%'},
93
166
  backgroundColor: 'none',
94
- curveType: 'function',
95
- colors : ['#089'],
96
- vAxis: {'gridlines': {'count' : 0}, 'textPosition' : 'none', 'baselineColor' : 'none', 'minValue' : 0 , 'maxValue' : 50},
167
+ bar: {groupWidth: "61.8%"},
168
+ colors : ['#089', 'silver' ],
169
+ vAxis: {'gridlines': {'count' : 0}, 'textPosition' : 'none', 'baselineColor' : 'none'},
97
170
  hAxis: { 'count' : 0, 'textPosition' : 'none', 'baselineColor' : 'none'},
98
- legend: {'position': 'none'}
171
+ legend: {'position': 'bottom'},
172
+ tooltip: {showColorCode: true, isHtml: true},
173
+ isStacked: true
174
+ }
175
+ var chart = new google.visualization.ColumnChart(element);
176
+ chart.draw(data, options);
177
+ }
178
+ })
179
+ }
180
+
181
+ function drawPieChart() {
182
+ elements = document.querySelectorAll(".inlinepie")
183
+ elements.forEach(element => {
184
+ var label = element.dataset.label;
185
+ var mydata = eval(element.innerText)
186
+ element.innerText = ''
187
+ element.classList.remove("hidden")
188
+ if(mydata.length >= 2) {
189
+ var data = google.visualization.arrayToDataTable(
190
+ mydata
191
+ )
192
+ var options = {
193
+ animation: {'startup': true, 'duration': 300},
194
+ annotations: {textStyle: {bold: true}, alwaysOutside: false },
195
+ width: 600,
196
+ height: 350,
197
+ backgroundColor: 'none',
198
+ bar: {groupWidth: "80%"},
199
+ colors : ['#089', 'silver', '#545B77' ],
200
+ axisTitlesPosition: 'none',
201
+ chartArea: {width:'90%', height: '85%'},
202
+ tooltip : {showColorCode: true},
203
+ vAxis: {gridlines: {count : 0}, textPosition : 'in', baselineColor : 'none', textStyle: {color: '#089', bold: true} },
204
+ hAxis: {gridlines: {count : 0}, textPosition : 'none', baselineColor : 'none'},
205
+ legend: {'position': 'bottom'},
206
+ isStacked: true,
207
+ bars: 'horizontal'
208
+ }
209
+ var chart = new google.visualization.PieChart(element);
210
+ if(mydata[1][1] == 0 && mydata[2][1] == 0){
211
+ return 0
212
+ }
213
+ chart.draw(data, options);
214
+ }
215
+ })
216
+ }
217
+
218
+
219
+ function drawStackedColumnChart() {
220
+ elements = document.querySelectorAll(".inlinestackedcolumn")
221
+ elements.forEach(element => {
222
+ var label = element.dataset.label;
223
+ var mydata = eval(element.innerText)
224
+ element.innerText = ''
225
+ element.classList.remove("hidden")
226
+ if(mydata.length > 1) {
227
+ console.log(mydata)
228
+ var data = google.visualization.arrayToDataTable(
229
+ mydata
230
+ )
231
+ var options = {
232
+ animation: {'startup': true, 'duration': 300},
233
+ annotations: {textStyle: {bold: true}, alwaysOutside: false },
234
+ width: 600,
235
+ height: 350,
236
+ backgroundColor: 'none',
237
+ bar: {groupWidth: "80%"},
238
+ colors : [ '#089', 'silver', '#545B77', 'silver'],
239
+ axisTitlesPosition: 'none',
240
+ chartArea: {width:'100%', height: '85%'},
241
+ tooltip : {showColorCode: true},
242
+ vAxis: {gridlines: {count : 0}, textPosition : 'none', baselineColor : 'none', textStyle: {color: '#089', bold: true} },
243
+ hAxis: {gridlines: {count : 0}, textPosition : 'none', baselineColor : 'none'},
244
+ legend: {'position': 'bottom'},
245
+ isStacked: true,
246
+ bars: 'horizontal'
99
247
  }
100
248
  var chart = new google.visualization.AreaChart(element);
101
249
  chart.draw(data, options);
102
- element.classList.remove("hidden")
103
250
  }
104
251
  })
105
252
  }
253
+
254
+
106
255
  function search_kd(el){
107
256
  //store the current value
108
257
  el.oldvalue = el.value
@@ -122,10 +271,11 @@
122
271
  el.timeout = window.setTimeout(function(){
123
272
  el.timeout = null
124
273
  window.location = locationWithParam('search', el.value)
125
- }, 300)
274
+ }, 500)
126
275
  }
127
276
 
128
277
  $(document).ready(function(){
278
+ /*
129
279
  el = $('#search-field')[0]
130
280
  el.focus()
131
281
  if(el.value && el.value.length > 0){
@@ -137,7 +287,8 @@
137
287
  var re = new RegExp("("+el.value+")", "giu")
138
288
  link.innerHTML = link.innerHTML.replaceAll(re, "<span class='token'>$1</span>") ;
139
289
  }
140
- }
290
+ }
291
+ */
141
292
  })
142
293
 
143
294
  function locationWithParam(param, value){
@@ -0,0 +1,118 @@
1
+ <div class = "row">
2
+
3
+ <div class = "col">
4
+ <div class="card">
5
+ <div class="card-header">
6
+ Subscriptions
7
+ </div>
8
+ <div class="card-body">
9
+ <h1><%=format(@subscription_count)%></h1>
10
+ </div>
11
+ </div>
12
+ </div>
13
+
14
+ <div class = "col">
15
+ <div class="card">
16
+ <div class="card-header">
17
+ Messages Received
18
+ </div>
19
+ <div class="card-body">
20
+ <h1><%=format(@broadcast_count)%></h1>
21
+ </div>
22
+ </div>
23
+ </div>
24
+
25
+ <div class = "col">
26
+ <div class="card">
27
+ <div class="card-header">
28
+ Messages delivered
29
+ </div>
30
+ <div class="card-body">
31
+ <h1><%=format(@message_count)%></h1>
32
+ </div>
33
+ </div>
34
+ </div>
35
+
36
+ </div>
37
+
38
+ <div class = "row">
39
+ &nbsp;<br/>
40
+ </div>
41
+
42
+ <div class="row">
43
+
44
+ <div class = "col">
45
+ <div class="card">
46
+ <div class="card-header">
47
+ Subscriptions over time
48
+ </div>
49
+ <div class="card-body">
50
+ <span class="hidden inlinecolumn">
51
+ <%=[["Time", "Count"]] + @subscriptions_over_time.to_a%>
52
+ </span>
53
+ </div>
54
+ </div>
55
+ </div>
56
+
57
+ <div class = "col">
58
+ <div class="card">
59
+ <div class="card-header">
60
+ Messages received/delivered over time
61
+ </div>
62
+ <div class="card-body">
63
+ <span class="hidden inlinestackedcolumn">
64
+ <%=[["Time", "Recieved Count", "Delivered Count"]] + @messages_over_time.to_a%>
65
+ </span>
66
+ </div>
67
+ </div>
68
+ </div>
69
+
70
+ </div>
71
+
72
+ <div class = "row">
73
+ &nbsp;<br/>
74
+ </div>
75
+
76
+ <div class = "row">
77
+
78
+ <div class = "col-6">
79
+ <div class="card">
80
+ <div class="card-header">
81
+ Channels with most subscriptions
82
+ </div>
83
+ <div class="card-body">
84
+ <table class="table">
85
+ <%@top_subscribed_channels.each do |r| %>
86
+ <tr>
87
+ <td><%=r['key']%></td>
88
+ <td align="right"><h6><%=format(r['rcount'])%>&nbsp;subs</h6></td>
89
+ </tr>
90
+ <% end %>
91
+ </table>
92
+ </div>
93
+ </div>
94
+ </div>
95
+
96
+ <div class = "col-6">
97
+ <div class="card">
98
+ <div class="card-header">
99
+ Channels with most messages delivered
100
+ </div>
101
+ <div class="card-body">
102
+ <table class="table">
103
+ <%@top_messaged_channels.each do |r| %>
104
+ <tr>
105
+ <td><%=r['key']%></td>
106
+ <td align="right"><h6><%=format(r['rcount'])%>&nbsp;messages</h6></td>
107
+ </tr>
108
+ <% end %>
109
+ </table>
110
+ </div>
111
+ </div>
112
+ </div>
113
+
114
+ </div>
115
+
116
+ <div class = "row">
117
+ &nbsp;<br/>
118
+ </div>
@@ -0,0 +1,144 @@
1
+
2
+ <div class = "row">
3
+
4
+ <div class = "col">
5
+ <div class="card">
6
+ <div class="card-header">
7
+ Current size / Max size
8
+ </div>
9
+ <div class="card-body">
10
+ <h1><%=format(round(@size))%>MB / <%=format(round(@max_size))%>MB <span class="fs-4"><%=round(@full)%>% full</span></h1>
11
+ </div>
12
+ </div>
13
+ </div>
14
+
15
+ <div class = "col">
16
+ <div class="card">
17
+ <div class="card-header">
18
+ Number of entries
19
+ </div>
20
+ <div class="card-body">
21
+ <h1><%=format(@entries)%></h1>
22
+ </div>
23
+ </div>
24
+ </div>
25
+
26
+ </div>
27
+
28
+ <div class = "row">
29
+ &nbsp;<br/>
30
+ </div>
31
+
32
+ <div class = "row">
33
+
34
+ <div class = "col">
35
+ <div class="card">
36
+ <div class="card-header">
37
+ Reads / Writes
38
+ </div>
39
+ <div class="card-body">
40
+ <h1><%=format(@reads)%> / <%=format(@writes)%> <span class="fs-4"><%=round(@reads.to_f/@writes) rescue 0%> reads/write</span></h1>
41
+ <hr/>
42
+ <span class="hidden inlinepie"><%=[["name", "value"],["reads", @reads],["writes", @writes]]%></span>
43
+ </div>
44
+ </div>
45
+ </div>
46
+
47
+ <div class = "col">
48
+ <div class="card">
49
+ <div class="card-header">
50
+ Read hits / Misses
51
+ </div>
52
+ <div class="card-body">
53
+ <h1><%=format(@hits)%> / <%=format(@misses)%> <span class="fs-4"><%=round(@hitrate*100)%>% hit rate</span></h1>
54
+ <hr/>
55
+ <span class="hidden inlinepie"><%=[["name", "value"],["hits", @hits],["misses", @misses]]%></span>
56
+ </div>
57
+ </div>
58
+ </div>
59
+
60
+ </div>
61
+
62
+ <div class = "row">
63
+ &nbsp;<br/>
64
+ </div>
65
+
66
+ <div class = "row">
67
+
68
+ <div class = "col">
69
+ <div class="card">
70
+ <div class="card-header">
71
+ Reads, writes over time
72
+ </div>
73
+ <div class="card-body">
74
+ <div class="hidden inlinecolumn">
75
+ <%=Oj.dump([["Time", "Reads", "Writes"]] + @reads_vs_writes)%>
76
+ </div>
77
+ </div>
78
+ </div>
79
+ </div>
80
+
81
+ <div class = "col">
82
+ <div class="card">
83
+ <div class="card-header">
84
+ Hits vs misses over time
85
+ </div>
86
+ <div class="card-body">
87
+ <span class="hidden inlinecolumn">
88
+ <%=Oj.dump([["Time", "Hits", "Misses"]] + @hits_vs_misses)%>
89
+ </span>
90
+ </div>
91
+ </div>
92
+ </div>
93
+
94
+ </div>
95
+
96
+ <div class = "row">
97
+ &nbsp;<br/>
98
+ </div>
99
+
100
+ <div class = "row">
101
+
102
+ <div class = "col">
103
+ <div class="card">
104
+ <div class="card-header">
105
+ Most read entries
106
+ </div>
107
+ <div class="card-body">
108
+ <table class="table">
109
+ <%@top_reads.each do |r| %>
110
+ <tr>
111
+ <td><%=r['key']%></td>
112
+ <td align="right"><h5><%=format(r['rcount'])%></h5></td>
113
+ </tr>
114
+ <% end %>
115
+ </table>
116
+ </div>
117
+ </div>
118
+ </div>
119
+
120
+ <div class = "col">
121
+ <div class="card">
122
+ <div class="card-header">
123
+ Most written entries
124
+ </div>
125
+ <div class="card-body">
126
+ <table class="table">
127
+ <%@top_writes.each do |r| %>
128
+ <tr>
129
+ <td><%=r['key']%></td>
130
+ <td align="right"><h5><%=format(r['rcount'])%></h5></td>
131
+ </tr>
132
+ <% end %>
133
+ </table>
134
+ </div>
135
+ </div>
136
+ </div>
137
+
138
+ </div>
139
+
140
+ <div class = "row">
141
+ &nbsp;<br/>
142
+ </div>
143
+
144
+