private static async Task <int> Main(string[] args) { var clientId = string.Empty; var clientSecret = string.Empty; var tenantId = string.Empty; var showHelp = false; var numberOfMonthsToAnalyze = 1; var outputFolder = Path.GetTempPath(); var openReport = false; var subscription = string.Empty; var onlyWithOverages = false; var optionSet = new OptionSet() .Add("clientId=", o => clientId = o) .Add("clientSecret=", o => clientSecret = o) .Add("tenantId=", o => tenantId = o) .Add("subscription=", o => subscription = o) .Add("numberOfMonths=", o => numberOfMonthsToAnalyze = int.Parse(o)) .Add("outputFolder=", o => outputFolder = o) .Add("openReport", o => openReport = o != null) .Add("onlyWithOverages", o => onlyWithOverages = true) .Add("h|?|help", o => showHelp = o != null); optionSet.Parse(args); Log.Logger = new LoggerConfiguration() .WriteTo.Console() .WriteTo.File($"log-{DateTime.UtcNow:yyyy_MM_dd_hh_mm}.txt") .CreateLogger(); if (showHelp) { ShowHelp(); return(0); } if (string.IsNullOrEmpty(subscription)) { Console.WriteLine("Mandatory parameter -subscriptionId is missing"); ShowHelp(); return(-1); } if (!Directory.Exists(outputFolder)) { Directory.CreateDirectory(outputFolder); } else if (Directory.GetFiles(outputFolder).Length > 0) { Console.WriteLine("Output directory is not empty"); return(-1); } var credentials = new CustomCredentials(clientId, clientSecret, tenantId); var subscriptions = await GetSubscriptions(subscription, credentials); await Process(credentials, subscriptions, numberOfMonthsToAnalyze, outputFolder, onlyWithOverages); var reportFile = CsvReporter.MergeReports(outputFolder); // Open report if (openReport && !string.IsNullOrEmpty(reportFile)) { var process = new Process { StartInfo = new ProcessStartInfo(reportFile) { UseShellExecute = true } }; process.Start(); } return(0); }
private static async Task Process(CustomCredentials credentials, ConcurrentQueue <string> subscriptions, int numberOfMonthsToAnalyze, string outputFolder, bool onlyWithOverages) { var processingThreads = subscriptions.Count > MaxNumberOfSubscriptionsToAnalyzeInParallel ? MaxNumberOfSubscriptionsToAnalyzeInParallel : subscriptions.Count; var threads = new List <Task>(processingThreads); var subscriptionsTotal = subscriptions.Count; var processed = 0; for (var i = 0; i < processingThreads; i++) { threads.Add(Task.Run(() => { while (subscriptions.TryDequeue(out var subscriptionId)) { try { var consumption = new ConsumptionProvider(credentials, subscriptionId); var usageDetails = consumption.GetConsumptionAsync(numberOfMonthsToAnalyze).GetAwaiter() .GetResult(); if (usageDetails.Count == 0) { Log.Warning($"No billing information found for subscription {subscriptionId}"); continue; } var consumptionAnalyzer = new ConsumptionAnalyzer(new ActivityLogProvider(credentials, subscriptionId), new ResourceProvider(credentials, subscriptionId), subscriptionId); var report = consumptionAnalyzer .AnalyzeConsumptionForDeletedResources(usageDetails, onlyWithOverages).GetAwaiter() .GetResult(); var reportFile = Path.Combine(outputFolder, $"consumption_{subscriptionId}_{DateTime.UtcNow:yyyy_MM_dd_hh_mm}.csv"); CsvReporter.WriteReport(report, reportFile); processed++; } catch (Exception exception) { Log.Error(exception, $"Exception while processing {subscriptionId}"); } } }).ContinueWith(t => { if (!t.IsCompletedSuccessfully) { Log.Error(t.Exception?.GetBaseException(), "Processing thread crashed"); } })); } using var timer = new Timer(data => Log.Information($"Processed ... {processed} of {subscriptionsTotal} subscriptions"), null, 0, 10000); await Task.WhenAll(threads); }