Skip to content

Commit f49765e

Browse files
committed
++ Logs table and page!
1 parent 389ec58 commit f49765e

File tree

8 files changed

+664
-1
lines changed

8 files changed

+664
-1
lines changed

.env

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,9 @@ AIRTABLE_SALES_SPY_PAT=patdgEwJHaWYEdX9v.7f582e3197071dba05ccd012fe337c79d8db216
22
AIRTABLE_SALES_SPY_BASE_ID=app0KekplH2tNZzH2
33

44
# Mysql
5-
5+
MYSQLDATABASE=railway
6+
MYSQLHOST=viaduct.proxy.rlwy.net
7+
MYSQLPASSWORD=TcqQAHOOlZBhuRcshGzVHUZwdXcjxjZz
8+
MYSQLPORT=30137
9+
MYSQLUSER=root
10+
MYSQL_URL=mysql://root:TcqQAHOOlZBhuRcshGzVHUZwdXcjxjZz@viaduct.proxy.rlwy.net:30137/railway

Pages/Logs/Index.cshtml

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
@page
2+
@model evantage.Pages.Logs.Index
3+
4+
@{
5+
}
6+
7+
<div>
8+
<section
9+
hx-get
10+
hx-trigger="load"
11+
hx-page-handler="AllLogs"
12+
hx-target="#all_logs">
13+
<label>
14+
All logs, Sorted by created_at:
15+
</label>
16+
<span id="all_logs"></span>
17+
</section>
18+
</div>

Pages/Logs/Index.cshtml.cs

Lines changed: 201 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,201 @@
1+
using System.Data;
2+
using System.Diagnostics;
3+
using System.Text;
4+
using CodeMechanic.Async;
5+
using CodeMechanic.Diagnostics;
6+
using CodeMechanic.Types;
7+
using Dapper;
8+
using Microsoft.AspNetCore.Mvc;
9+
using Microsoft.AspNetCore.Mvc.RazorPages;
10+
using MySqlConnector;
11+
12+
namespace evantage.Pages.Logs;
13+
14+
public class Index : PageModel
15+
{
16+
private static string connectionString;
17+
18+
public void OnGet()
19+
{
20+
}
21+
22+
public async Task<IActionResult> OnGetAllLogs()
23+
{
24+
string query =
25+
"""
26+
select operation_name,
27+
exception_text,
28+
payload,
29+
diff,
30+
sql_parameters,
31+
table_name,
32+
breadcrumb
33+
from logs
34+
order by created_at asc, modified_at asc;
35+
"""
36+
;
37+
string connectionstring = GetConnectionString();
38+
using var connection = new MySqlConnection(connectionstring);
39+
40+
var results = connection
41+
.Query<LogRecord>(query
42+
, commandType: CommandType.Text
43+
)
44+
.ToList();
45+
46+
int count = results.Count;
47+
48+
// return Content($"{count}");
49+
return Partial("_LogsTable", results);
50+
}
51+
52+
private static string GetConnectionString()
53+
{
54+
var connectionString = new MySqlConnectionStringBuilder()
55+
{
56+
Database = Environment.GetEnvironmentVariable("MYSQLDATABASE"),
57+
Server = Environment.GetEnvironmentVariable("MYSQLHOST"),
58+
Password = Environment.GetEnvironmentVariable("MYSQLPASSWORD"),
59+
UserID = Environment.GetEnvironmentVariable("MYSQLUSER"),
60+
Port = (uint)Environment.GetEnvironmentVariable("MYSQLPORT").ToInt()
61+
}.ToString();
62+
63+
if (connectionString == null) throw new ArgumentNullException(nameof(connectionString));
64+
return connectionString;
65+
}
66+
67+
private async Task<List<LogRecord>> BulkUpsertLogs(List<LogRecord> logRecords)
68+
{
69+
var batch_size =
70+
1000; //(int)Math.Round(Math.Log2(logRecords.Count * 1.0) * Math.Log10(logRecords.Count) * 100, 1);
71+
Console.WriteLine("batch size :>> " + batch_size);
72+
var Q = new SerialQueue();
73+
Console.WriteLine("Running Q of bulk upserts ... ");
74+
Stopwatch watch = new Stopwatch();
75+
watch.Start();
76+
var tasks = logRecords
77+
.Batch(batch_size)
78+
.Select(log_batch => Q
79+
.Enqueue(async () => await UpsertLogs(log_batch, debug_mode: false)));
80+
81+
await Task.WhenAll(tasks);
82+
watch.Stop();
83+
watch.PrintRuntime($"Done upserting {logRecords.Count} logs! ");
84+
return logRecords;
85+
}
86+
87+
private async Task<List<LogRecord>> UpsertLogs(
88+
IEnumerable<LogRecord> logRecords
89+
, bool debug_mode = false
90+
)
91+
{
92+
var insert_values = logRecords
93+
.Aggregate(new StringBuilder(), (builder, next) =>
94+
{
95+
builder
96+
.AppendLine($"( '{next.application_name}'")
97+
.AppendLine($", '{next.database_name}' ")
98+
.AppendLine($", '{next.exception_text}' ")
99+
.AppendLine($", '{next.breadcrumb}' ")
100+
.AppendLine($", '{next.issue_url}' ")
101+
.AppendLine($", '{next.created_by}' ")
102+
.AppendLine($", '{next.modified_by}' ")
103+
.AppendLine($", null")
104+
.AppendLine($", null")
105+
.AppendLine($", '{next.is_archived}' ")
106+
.AppendLine($", '{next.is_deleted}' ")
107+
.AppendLine($", '{next.is_enabled}' ")
108+
.AppendLine($")")
109+
.ToString()
110+
.Trim();
111+
builder.Append(",");
112+
return builder;
113+
}).ToString();
114+
115+
if (debug_mode) Console.WriteLine("values query :>> " + insert_values);
116+
117+
string insert_begin = """
118+
insert into logs
119+
(
120+
table_name
121+
, database_name
122+
, exception_text
123+
, breadcrumb
124+
, issue_url
125+
, created_by
126+
, modified_by
127+
, created_at
128+
, modified_at
129+
, is_deleted
130+
, is_archived
131+
, is_enabled
132+
)
133+
values
134+
""";
135+
136+
var query = StringBuilderExtensions.RemoveFromEnd(new StringBuilder()
137+
.AppendLine(insert_begin)
138+
.AppendLine(insert_values), 2) // remove last comma
139+
.Append(";") // adds the delimiter for mysql
140+
.ToString();
141+
142+
if (debug_mode) Console.WriteLine("full query :>> " + query);
143+
144+
try
145+
{
146+
var connectionString = GetConnectionString();
147+
using var connection = new MySqlConnection(connectionString);
148+
149+
var results = connection
150+
.Query<LogRecord>(query
151+
, commandType: CommandType.Text
152+
)
153+
.ToList();
154+
155+
return results ?? new List<LogRecord>();
156+
}
157+
catch (Exception e)
158+
{
159+
Console.WriteLine(e);
160+
WriteLocalLogfile(e.ToString() + query);
161+
throw;
162+
}
163+
}
164+
165+
private static void WriteLocalLogfile(string content)
166+
{
167+
var cwd = Environment.CurrentDirectory;
168+
string filepath = Path.Combine(cwd, "Admin.log");
169+
Console.WriteLine("writing to :>> " + filepath);
170+
System.IO.File.WriteAllText(filepath, content);
171+
}
172+
}
173+
174+
public sealed class LogRecord
175+
{
176+
public string id { get; set; } = string.Empty;
177+
public string exception_text { get; set; } = string.Empty;
178+
public string exception_message { get; set; } = "OOOPS!"; // = string.Empty;
179+
180+
public string exception_severity { get; set; } = "HIGH";
181+
182+
public string sql_parameters { get; set; } = string.Empty;
183+
public string payload { get; set; } = string.Empty;
184+
public string diff { get; set; } = "{}";
185+
public string operation_name { get; set; } = string.Empty;
186+
public string breadcrumb { get; set; } = string.Empty;
187+
public string table_name { get; set; } = string.Empty;
188+
public string server_name { get; set; } = string.Empty;
189+
public string database_name { get; set; } = string.Empty;
190+
public string application_name { get; set; } = string.Empty;
191+
public string modified_by { get; set; } = string.Empty;
192+
public string created_by { get; set; } = string.Empty;
193+
public DateTime modified_at { get; set; }
194+
public DateTime created_at { get; set; }
195+
196+
public string commit_url { get; set; } = string.Empty;
197+
public string issue_url { get; set; } = string.Empty;
198+
public bool is_deleted { get; set; }
199+
public bool is_archived { get; set; }
200+
public bool is_enabled { get; set; }
201+
}

Pages/Logs/_LogsTable.cshtml

Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
@using CodeMechanic.Types
2+
@model List<LogRecord>
3+
@{
4+
var rows = Model;
5+
}
6+
7+
<section id="splunky_logs" class="vertical-padding">
8+
<div class="overflow-x-auto wrapper">
9+
<b>Rows: @rows.Count</b>
10+
11+
<table class="table w-full">
12+
<thead>
13+
<tr>
14+
<th></th>
15+
<th>Table</th>
16+
<th>Exception</th>
17+
<th>Diff</th>
18+
<th>Params</th>
19+
<th>Details</th>
20+
</tr>
21+
</thead>
22+
<tbody>
23+
@foreach (var row in rows.Take(100))
24+
{
25+
<tr>
26+
<th>
27+
<label>
28+
<input type="checkbox" class="checkbox"/>
29+
</label>
30+
</th>
31+
<td>
32+
<div class="flex items-center gap-3">
33+
<div class="avatar">
34+
<div class="bg-neutral text-neutral-content rounded-full w-12">
35+
<span class="text-3xl">@row.table_name.ToUpperInvariant()[0]</span>
36+
</div>
37+
</div>
38+
<div>
39+
<div class="font-bold text-secondary">@row.table_name</div>
40+
<div class="text-sm opacity-50 text-primary">@row.database_name</div>
41+
</div>
42+
</div>
43+
</td>
44+
<td>
45+
@row.operation_name
46+
<br/>
47+
<span class="badge badge-ghost badge-sm">@row.exception_message</span>
48+
</td>
49+
<td>@row.diff</td>
50+
<td>@row.sql_parameters</td>
51+
<th x-data="{show_details = false}">
52+
<button class="btn btn-ghost btn-xs" x-on:click="show_details=!show_details">
53+
Details
54+
</button>
55+
</th>
56+
</tr>
57+
}
58+
</tbody>
59+
</table>
60+
</div>
61+
</section>
62+
<style>
63+
.wrapper {
64+
width: min(900px, 100% - 3rem);
65+
/*margin-inline: auto;*/
66+
}
67+
table {
68+
border-collapse: collapse;
69+
}
70+
71+
th,td {
72+
padding: 1rem;
73+
/*background: #002f4a;*/
74+
}
75+
76+
caption,th {
77+
text-align: left;
78+
}
79+
80+
caption {
81+
/*background: hsl(0, 0%, 0%);*/
82+
font-size: 1rem;
83+
font-weight: 700;
84+
text-transform: uppercase;
85+
}
86+
87+
@@media(max-width: 650px) {
88+
th {
89+
display: none;
90+
}
91+
td {
92+
display: block;
93+
padding: 0.75rem 1rem;
94+
}
95+
96+
td:first-child {
97+
padding-top: 2rem;
98+
}
99+
td:last-child {
100+
padding-bottom: 2rem;
101+
}
102+
103+
td::before {
104+
content: attr(data-cell) ": ";
105+
font-weight: 700;
106+
text-transform: capitalize;
107+
}
108+
109+
/*td:nth-of-type(1)::before {*/
110+
/* content: "retailer"*/
111+
/*}*/
112+
}
113+
114+
</style>

Pages/Logs/create-log.sql

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
drop procedure if exists CreateLog;
2+
DELIMITER ^_^
3+
CREATE PROCEDURE CreateLog(
4+
_table_name varchar(250),
5+
_exception TEXT,
6+
_operation varchar(250)
7+
)
8+
BEGIN
9+
10+
insert into logs (table_name, exception_text, operation_name) values (_table_name, _exception, _operation);
11+
12+
END ^_^
13+
14+
DELIMITER ;
15+
16+
call CreateLog('airtable.jobs', 'exception', 'onget()');
17+
18+
select operation_name,
19+
exception_text,
20+
payload,
21+
diff,
22+
sql_parameters,
23+
table_name,
24+
breadcrumb
25+
from logs
26+
order by created_at asc, modified_at asc;
27+
28+
29+
# select * from logs;
30+
31+
# call SearchLogs('zzz', null, null, null);
32+
33+
# delete from logs where id > 0;
34+

0 commit comments

Comments
 (0)