Skip to content

Commit

Permalink
feat(cli): support replace cdn domain of html output (#66)
Browse files Browse the repository at this point in the history
Signed-off-by: catcherwong <[email protected]>
  • Loading branch information
catcherwong authored Aug 26, 2024
1 parent e9d6271 commit d05b758
Show file tree
Hide file tree
Showing 3 changed files with 20 additions and 3 deletions.
11 changes: 11 additions & 0 deletions src/RDBCli/Commands/CommonCLIOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -172,5 +172,16 @@ public static Option<int> SepPrefixCountOption()

return option;
}

public static Option<string> CDNOption()
{
Option<string> option =
new Option<string>(
aliases: new string[] { "--cdn" },
getDefaultValue: () => "unpkg.com",
description: "The cdn domain for html output");

return option;
}
}
}
10 changes: 8 additions & 2 deletions src/RDBCli/Commands/MemoryCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ internal class MemoryCommand : Command
private static Option<bool?> _isPermanentOption = CommonCLIOptions.IsPermanentOption();
private static Option<bool?> _isIgnoreFieldOfLargestElemOption = CommonCLIOptions.IsIgnoreFieldOfLargestElemOption();
private static Option<bool?> _keySuffixEnableOption = CommonCLIOptions.KeySuffixEnableOption();
private static Option<string> _cdnOption = CommonCLIOptions.CDNOption();
private static Argument<string> _fileArg = CommonCLIArguments.FileArgument();

public MemoryCommand()
Expand All @@ -41,6 +42,7 @@ public MemoryCommand()
this.AddOption(_isPermanentOption);
this.AddOption(_isIgnoreFieldOfLargestElemOption);
this.AddOption(_keySuffixEnableOption);
this.AddOption(_cdnOption);
this.AddArgument(_fileArg);

this.SetHandler((InvocationContext context) =>
Expand Down Expand Up @@ -98,14 +100,14 @@ private void Do(InvocationContext context, CommandOptions options)
dict.permCount = (int)(perm?.Num ?? 0);
dict.permMem = (long)(perm?.Bytes ?? 0);

var path = WriteFile(dict, options.Output, options.OutputType);
var path = WriteFile(dict, options.Output, options.OutputType, options.CDN);

sw.Stop();
console.WriteLine($"total cost: {sw.ElapsedMilliseconds}ms");
console.WriteLine($"result path: {path}\n");
}

private string WriteFile(MemoryAnslysisResult dict, string output, string type)
private string WriteFile(MemoryAnslysisResult dict, string output, string type, string cdn)
{
var path = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, $"res.{type}");

Expand Down Expand Up @@ -137,6 +139,7 @@ private string WriteFile(MemoryAnslysisResult dict, string output, string type)
{
var str = JsonSerializer.Serialize(dict, typeof(MemoryAnslysisResult), context);
var tpl = CommonHelper.TplHtmlString;
tpl = tpl.Replace("{{CDNDOMAIN}}", cdn);
tpl = tpl.Replace("{{CLIDATA}}", str);

bytes = System.Text.Encoding.UTF8.GetBytes(tpl);
Expand Down Expand Up @@ -182,6 +185,7 @@ private class CommandOptions
public int SepPrefixCount { get; set; }
public bool? IsIgnoreFole { get; set; }
public bool? keySuffixEnable { get; set; }
public string CDN { get; set; }


public static CommandOptions FromContext(InvocationContext context)
Expand All @@ -199,6 +203,7 @@ public static CommandOptions FromContext(InvocationContext context)
var isPermanent = context.ParseResult.GetValueForOption<bool?>(_isPermanentOption);
var isIgnoreFole = context.ParseResult.GetValueForOption<bool?>(_isIgnoreFieldOfLargestElemOption);
var keySuffixEnable = context.ParseResult.GetValueForOption<bool?>(_keySuffixEnableOption);
var cdn = context.ParseResult.GetValueForOption<string>(_cdnOption);

var parseFilter = new RDBParser.ParserFilter()
{
Expand All @@ -220,6 +225,7 @@ public static CommandOptions FromContext(InvocationContext context)
SepPrefixCount = sepPrefixCount,
IsIgnoreFole = isIgnoreFole,
keySuffixEnable = keySuffixEnable,
CDN = cdn,
};
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/RDBCli/Helpers/CommonHelper.Const.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ namespace RDBCli
internal static partial class CommonHelper
{
// compress Tpl/tpl.html to get this value.
internal const string TplHtmlString = "<!DOCTYPE html><html lang=\"en\"><head><meta charset=\"UTF-8\"><meta http-equiv=\"X-UA-Compatible\"content=\"IE=edge\"><meta name=\"viewport\"content=\"width=device-width, initial-scale=1.0\"><title>rdb-cli,offline key analysis</title><link rel=\"stylesheet\"href=\"https://unpkg.com/[email protected]/dist/css/bootstrap.min.css\"/><link rel=\"stylesheet\"href=\"https://unpkg.com/[email protected]/dist/bootstrap-table.min.css\"><style>.bootstrap-table.fixed-table-pagination>.pagination-detail.page-list{display:none}</style><script src=\"https://unpkg.com/[email protected]/dist/jquery.min.js\"></script><script src=\"https://unpkg.com/[email protected]/dist/js/bootstrap.min.js\"></script><script src=\"https://unpkg.com/[email protected]/dist/chart.min.js\"></script><script src=\"https://unpkg.com/[email protected]/dist/bootstrap-table.min.js\"></script></head><body><nav class=\"navbar navbar-expand-sm bg-info navbar-dark\"><div class=\"ms-auto me-auto\"><a class=\"navbar-brand fs-4\"href=\"https://github.com/catcherwong/rdb-tools\">rdb-cli</a></div></nav><div class=\"container\"><br/><div class=\"page-header border-start border-light border-3\"><h3>Basic Information</h3></div><br/><div class=\"row\"><div class=\"col-md-4\"><div class=\"card\"style=\"height: 100px;\"><div class=\"card-body text-center\"><div class=\"lead display-7\">RDB Version:<b id=\"rdbVer\"></b></div><div class=\"lead display-7\">Redis Version:<b id=\"redisVer\"></b></div></div></div></div><div class=\"col-md-4\"><div class=\"card\"style=\"height: 100px;\"><div class=\"card-body text-center\"><div id=\"totalKeyBytes\"class=\"lead text-primary display-6\"></div><p class=\"small text-muted\">Total Memory Usage of Keys</p></div></div></div><div class=\"col-md-4\"><div class=\"card\"style=\"height: 100px;\"><div class=\"card-body text-center\"><div id=\"totalKeyNum\"class=\"lead text-primary display-6\"></div><p class=\"small text-muted\">Total Number of Keys</p></div></div></div></div><br/><div class=\"row\"><div class=\"col-md-3\"><div class=\"card\"style=\"height: 100px;\"><div class=\"card-body text-center\"><div id=\"expKeyNum\"class=\"lead text-primary display-6\"></div><p class=\"small text-muted\">Expired Keys</p></div></div></div><div class=\"col-md-3\"><div class=\"card\"style=\"height: 100px;\"><div class=\"card-body text-center\"><div id=\"expKeyBytes\"class=\"lead text-primary display-6\"></div><p class=\"small text-muted\">Memory Usage by Expired Keys</p></div></div></div><div class=\"col-md-3\"><div class=\"card\"style=\"height: 100px;\"><div class=\"card-body text-center\"><div id=\"permKeyNum\"class=\"lead text-primary display-6\"></div><p class=\"small text-muted\">Permanent Keys</p></div></div></div><div class=\"col-md-3\"><div class=\"card\"style=\"height: 100px;\"><div class=\"card-body text-center\"><div id=\"permKeyBytes\"class=\"lead text-primary display-6\"></div><p class=\"small text-muted\">Memory Usage by Permanent Keys</p></div></div></div></div><br/><div class=\"page-header border-start border-light border-3\"><h3>Details Information</h3></div><br/><div class=\"row\"><div class=\"col-md-6\"><canvas id=\"typeNum\"width=\"400\"height=\"400\"></canvas></div><div class=\"col-md-6\"><canvas id=\"typeByte\"width=\"400\"height=\"400\"></canvas></div></div><br/><br/><div class=\"row\"><div class=\"col-md-6\"><canvas id=\"expiryNum\"width=\"400\"height=\"400\"></canvas></div><div class=\"col-md-6\"><canvas id=\"expiryByte\"width=\"400\"height=\"400\"></canvas></div></div><br/><br/><div class=\"row\"><div class=\"col-md-6\"><canvas id=\"idleOrFreqNum\"width=\"400\"height=\"400\"></canvas></div><div class=\"col-md-6\"><canvas id=\"idleOrFreqByte\"width=\"400\"height=\"400\"></canvas></div></div><br/><br/><div class=\"row\"><div class=\"col-md-12\"><ul class=\"nav nav-tabs\"role=\"tablist\"><li class=\"nav-item\"><a class=\"nav-link active\"data-bs-toggle=\"tab\"href=\"#topPrefix\">Top Key Prefixes</a></li><li class=\"nav-item\"><a class=\"nav-link\"data-bs-toggle=\"tab\"href=\"#topBigKeys\">Top Big Keys</a></li><li class=\"nav-item\"id=\"tbStreams\"><a class=\"nav-link\"data-bs-toggle=\"tab\"href=\"#streams\">Top Streams</a></li><li class=\"nav-item\"id=\"tbFunctions\"><a class=\"nav-link\"data-bs-toggle=\"tab\"href=\"#functions\">Functions</a></li></ul><div class=\"tab-content\"><div id=\"topBigKeys\"class=\"container tab-pane fade\"><br><table id=\"topBigKeysTable\"></table></div><div id=\"topPrefix\"class=\"container tab-pane active\"><br><table id=\"topPrefixTable\"></table></div><div id=\"functions\"class=\"container tab-pane fade\"><br><table id=\"functionTable\"></table></div><div id=\"streams\"class=\"container tab-pane fade\"><br><table id=\"streamsTable\"></table></div></div></div></div></div>" +
internal const string TplHtmlString = "<!DOCTYPE html><html lang=\"en\"><head><meta charset=\"UTF-8\"><meta http-equiv=\"X-UA-Compatible\"content=\"IE=edge\"><meta name=\"viewport\"content=\"width=device-width, initial-scale=1.0\"><title>rdb-cli,offline key analysis</title><link rel=\"stylesheet\"href=\"https://{{CDNDOMAIN}}/[email protected]/dist/css/bootstrap.min.css\"/><link rel=\"stylesheet\"href=\"https://{{CDNDOMAIN}}/[email protected]/dist/bootstrap-table.min.css\"><style>.bootstrap-table.fixed-table-pagination>.pagination-detail.page-list{display:none}</style><script src=\"https://{{CDNDOMAIN}}/[email protected]/dist/jquery.min.js\"></script><script src=\"https://{{CDNDOMAIN}}/[email protected]/dist/js/bootstrap.min.js\"></script><script src=\"https://{{CDNDOMAIN}}/[email protected]/dist/chart.min.js\"></script><script src=\"https://{{CDNDOMAIN}}/[email protected]/dist/bootstrap-table.min.js\"></script></head><body><nav class=\"navbar navbar-expand-sm bg-info navbar-dark\"><div class=\"ms-auto me-auto\"><a class=\"navbar-brand fs-4\"href=\"https://github.com/catcherwong/rdb-tools\">rdb-cli</a></div></nav><div class=\"container\"><br/><div class=\"page-header border-start border-light border-3\"><h3>Basic Information</h3></div><br/><div class=\"row\"><div class=\"col-md-4\"><div class=\"card\"style=\"height: 100px;\"><div class=\"card-body text-center\"><div class=\"lead display-7\">RDB Version:<b id=\"rdbVer\"></b></div><div class=\"lead display-7\">Redis Version:<b id=\"redisVer\"></b></div></div></div></div><div class=\"col-md-4\"><div class=\"card\"style=\"height: 100px;\"><div class=\"card-body text-center\"><div id=\"totalKeyBytes\"class=\"lead text-primary display-6\"></div><p class=\"small text-muted\">Total Memory Usage of Keys</p></div></div></div><div class=\"col-md-4\"><div class=\"card\"style=\"height: 100px;\"><div class=\"card-body text-center\"><div id=\"totalKeyNum\"class=\"lead text-primary display-6\"></div><p class=\"small text-muted\">Total Number of Keys</p></div></div></div></div><br/><div class=\"row\"><div class=\"col-md-3\"><div class=\"card\"style=\"height: 100px;\"><div class=\"card-body text-center\"><div id=\"expKeyNum\"class=\"lead text-primary display-6\"></div><p class=\"small text-muted\">Expired Keys</p></div></div></div><div class=\"col-md-3\"><div class=\"card\"style=\"height: 100px;\"><div class=\"card-body text-center\"><div id=\"expKeyBytes\"class=\"lead text-primary display-6\"></div><p class=\"small text-muted\">Memory Usage by Expired Keys</p></div></div></div><div class=\"col-md-3\"><div class=\"card\"style=\"height: 100px;\"><div class=\"card-body text-center\"><div id=\"permKeyNum\"class=\"lead text-primary display-6\"></div><p class=\"small text-muted\">Permanent Keys</p></div></div></div><div class=\"col-md-3\"><div class=\"card\"style=\"height: 100px;\"><div class=\"card-body text-center\"><div id=\"permKeyBytes\"class=\"lead text-primary display-6\"></div><p class=\"small text-muted\">Memory Usage by Permanent Keys</p></div></div></div></div><br/><div class=\"page-header border-start border-light border-3\"><h3>Details Information</h3></div><br/><div class=\"row\"><div class=\"col-md-6\"><canvas id=\"typeNum\"width=\"400\"height=\"400\"></canvas></div><div class=\"col-md-6\"><canvas id=\"typeByte\"width=\"400\"height=\"400\"></canvas></div></div><br/><br/><div class=\"row\"><div class=\"col-md-6\"><canvas id=\"expiryNum\"width=\"400\"height=\"400\"></canvas></div><div class=\"col-md-6\"><canvas id=\"expiryByte\"width=\"400\"height=\"400\"></canvas></div></div><br/><br/><div class=\"row\"><div class=\"col-md-6\"><canvas id=\"idleOrFreqNum\"width=\"400\"height=\"400\"></canvas></div><div class=\"col-md-6\"><canvas id=\"idleOrFreqByte\"width=\"400\"height=\"400\"></canvas></div></div><br/><br/><div class=\"row\"><div class=\"col-md-12\"><ul class=\"nav nav-tabs\"role=\"tablist\"><li class=\"nav-item\"><a class=\"nav-link active\"data-bs-toggle=\"tab\"href=\"#topPrefix\">Top Key Prefixes</a></li><li class=\"nav-item\"><a class=\"nav-link\"data-bs-toggle=\"tab\"href=\"#topBigKeys\">Top Big Keys</a></li><li class=\"nav-item\"id=\"tbStreams\"><a class=\"nav-link\"data-bs-toggle=\"tab\"href=\"#streams\">Top Streams</a></li><li class=\"nav-item\"id=\"tbFunctions\"><a class=\"nav-link\"data-bs-toggle=\"tab\"href=\"#functions\">Functions</a></li></ul><div class=\"tab-content\"><div id=\"topBigKeys\"class=\"container tab-pane fade\"><br><table id=\"topBigKeysTable\"></table></div><div id=\"topPrefix\"class=\"container tab-pane active\"><br><table id=\"topPrefixTable\"></table></div><div id=\"functions\"class=\"container tab-pane fade\"><br><table id=\"functionTable\"></table></div><div id=\"streams\"class=\"container tab-pane fade\"><br><table id=\"streamsTable\"></table></div></div></div></div></div>" +
"<script>const cliData={{CLIDATA}};$('#rdbVer').text(cliData.rdbVer);$('#redisVer').text(cliData.redisVer);$('#totalKeyBytes').text(formatBytes(cliData.usedMem));$('#totalKeyNum').text(formatNumber(cliData.count));$('#expKeyNum').text(formatNumber(cliData.expCount));$('#permKeyNum').text(formatNumber(cliData.permCount));$('#expKeyBytes').text(formatBytes(cliData.expMem));$('#permKeyBytes').text(formatBytes(cliData.permMem));buildTypeNumChart();buildTypeByteChart();buildExpiryNumChart();buildExpiryByteChart();buildIdleOrFreqNumChart();buildIdleOrFreqByteChart();$('#topPrefixTable').bootstrapTable({data:cliData.largestKeyPrefix,columns:[{field:'Prefix',title:'Key Prefix'},{field:'Type',title:'Type'},{field:'Bytes',title:'Memory Usage',sortable:true,formatter:function(val,row,index){return formatBytes(val)}},{field:'Num',title:'Keys',sortable:true,formatter:function(val,row,index){return formatNumber(val)}},{field:'Elements',title:'Elements',sortable:true,formatter:function(val,row,index){return formatNumber(val)}}],pagination:true,pageSize:10,pageNumber:1,});$('#topBigKeysTable').bootstrapTable({data:cliData.largestRecords,columns:[{field:'Key',title:'Key'},{field:'Type',title:'Type'},{field:'Encoding',title:'Encoding'},{field:'Bytes',title:'Memory Usage',sortable:true,formatter:function(val,row,index){return formatBytes(val)}},{field:'Database',title:'Database'},{field:'Expiry',title:'Validity Period',formatter:function(val,row,index){return formatExpiry(val)}},{field:'NumOfElem',title:'Elements',sortable:true,formatter:function(val,row,index){return formatNumber(val)}},{field:'LenOfLargestElem',title:'Length of Largest Element',sortable:true,}],pagination:true,pageSize:10,pageNumber:1,});$('#functionTable').bootstrapTable({data:cliData.functions,columns:[{field:'Engine',title:'Engine'},{field:'LibraryName',title:'Library Name'}],pagination:true,pageSize:10,pageNumber:1,});$('#streamsTable').bootstrapTable({data:cliData.largestStreams,columns:[{field:'Key',title:'Key'},{field:'Length',title:'Length',sortable:true,},{field:'LastId',title:'LastId'},{field:'FirstId',title:'FirstId'},{field:'MaxDeletedEntryId',title:'Max Deleted EntryId'},{field:'EntriesAdded',title:'Entries Added',sortable:true,},{field:'CGroups',title:'Consumer Groups',sortable:true,}],pagination:true,pageSize:10,pageNumber:1,});function buildTypeNumChart(){const typeChartLabels=cliData.typeRecords.map(item=>item.Type);const typeNumData=cliData.typeRecords.map(item=>item.Num);buildBarChart(typeChartLabels,typeNumData,'Keys','Distribution of Keys',formatNumber,'typeNum')};function buildTypeByteChart(){const typeChartLabels=cliData.typeRecords.map(item=>item.Type);const typeByteData=cliData.typeRecords.map(item=>item.Bytes);buildBarChart(typeChartLabels,typeByteData,'Memory Usage of Keys','Memory Usage of Keys',formatBytes,'typeByte')};function buildExpiryNumChart(){const expiryLabels=cliData.expiryInfo.map(item=>item.Expiry);const expiryData=cliData.expiryInfo.map(item=>item.Num);buildBarChart(expiryLabels,expiryData,'Total Keys','Distribution of Key Expiration Time (Quantity)',formatNumber,'expiryNum')};function buildExpiryByteChart(){const expiryLabels=cliData.expiryInfo.map(item=>item.Expiry);const expiryData=cliData.expiryInfo.map(item=>item.Bytes);buildBarChart(expiryLabels,expiryData,'Memory Usage of Keys','Distribution of Key Expiration Time (Memory)',formatBytes,'expiryByte')};function buildIdleOrFreqNumChart(){const labels=cliData.idleOrFreqInfo.map(item=>item.Category);const data=cliData.idleOrFreqInfo.map(item=>item.Num);buildBarChart(labels,data,'Total Keys','Distribution of Key Idle or Freq (Quantity)',formatNumber,'idleOrFreqNum')};function buildIdleOrFreqByteChart(){const labels=cliData.idleOrFreqInfo.map(item=>item.Category);const data=cliData.idleOrFreqInfo.map(item=>item.Bytes);buildBarChart(labels,data,'Memory Usage of Keys','Distribution of Key Idle or Freq (Memory)',formatBytes,'idleOrFreqByte')};function buildBarChart(labels,dsData,dsLabel,title,formaterFunc,eleId){const data={labels:labels,datasets:[{data:dsData,label:dsLabel,minBarLength:5,}]};const config={type:'bar',data:data,options:{responsive:true,plugins:{legend:{display:false,},title:{display:true,text:title}},scales:{y:{beginAtZero:true,ticks:{callback:function(label,index,labels){return formaterFunc(label)}}}}}};const ctx=document.getElementById(eleId);new Chart(ctx,config)};function formatNumber(num){const k=1000;const m=1000000;const b=1000000000;if(num<k){return num}else if(num>k&&num<m){return(num/k).toFixed(1)+'K'}else if(num>=m&&num<=b){return(num/m).toFixed(1)+'M'}else{return(num/b).toFixed(1)+'B'}};function formatBytes(bytes){const kb=1024;const mb=1024*1024;const gb=1024*1024*1024;if(bytes<kb){return bytes.toFixed(1)+'B'}if(bytes>=kb&&bytes<mb){return(bytes/kb).toFixed(1)+'KB'}else if(bytes>=mb&&bytes<=gb){return(bytes/mb).toFixed(1)+'MB'}else{return(bytes/gb).toFixed(1)+'GB'}};function formatExpiry(time){if(time==0){return'Permanent'}else{let date=new Date(time);let year=date.getFullYear();let month=date.getMonth()+1;let day=date.getDate();let hour=date.getHours();let min=date.getMinutes();let second=date.getSeconds();return year+'-'+month+'-'+day+' '+hour+':'+min+':'+second}};</script>" +
"</body></html>";

Expand Down

0 comments on commit d05b758

Please sign in to comment.