From 9ad2a4798be0a60ffd421ad3e182b9a32240098b Mon Sep 17 00:00:00 2001 From: Gyula Kerezsi Date: Thu, 15 Dec 2016 16:48:53 +0200 Subject: [PATCH] adds code --- CloudWatchLogUploader/BaseHelper.cs | 41 ++++++ .../CloudWatchLogUploader.csproj | 36 +++++ CloudWatchLogUploader/CommandOptions.cs | 35 +++++ CloudWatchLogUploader/DebugLogger.cs | 87 ++++++++++++ CloudWatchLogUploader/FodyWeavers.xml | 5 + CloudWatchLogUploader/LogGroupHelper.cs | 88 ++++++++++++ CloudWatchLogUploader/LogStreamHelper.cs | 125 ++++++++++++++++++ CloudWatchLogUploader/Program.cs | 19 ++- CloudWatchLogUploader/packages.config | 8 ++ 9 files changed, 440 insertions(+), 4 deletions(-) create mode 100644 CloudWatchLogUploader/BaseHelper.cs create mode 100644 CloudWatchLogUploader/CommandOptions.cs create mode 100644 CloudWatchLogUploader/DebugLogger.cs create mode 100644 CloudWatchLogUploader/FodyWeavers.xml create mode 100644 CloudWatchLogUploader/LogGroupHelper.cs create mode 100644 CloudWatchLogUploader/LogStreamHelper.cs create mode 100644 CloudWatchLogUploader/packages.config diff --git a/CloudWatchLogUploader/BaseHelper.cs b/CloudWatchLogUploader/BaseHelper.cs new file mode 100644 index 0000000..a50a287 --- /dev/null +++ b/CloudWatchLogUploader/BaseHelper.cs @@ -0,0 +1,41 @@ +using System; +using Amazon.CloudWatchLogs; + +namespace CloudWatchLogUploader +{ + internal abstract class BaseHelper + { + protected readonly AmazonCloudWatchLogsClient client; + public BaseHelper(AmazonCloudWatchLogsClient client) + { + this.client = client; + } + + protected bool GetYesOrNo() + { + ConsoleKeyInfo key; + do + { + key = Console.ReadKey(true); + } while (key.Key == ConsoleKey.Enter || key.Key == ConsoleKey.Y || key.Key == ConsoleKey.N); + + switch (key.Key) + { + case ConsoleKey.Y: + return true; + case ConsoleKey.N: + default: + return false; + } + } + + protected int ReadIntBetween(string message, int min, int max) + { + Console.Write(message); + int num; + while (!int.TryParse(Console.ReadLine(), out num) && num >= min && num <= max) + Console.Write(Environment.NewLine + "Please enter an integer between " + min + " and " + max); + return num; + } + } +} diff --git a/CloudWatchLogUploader/CloudWatchLogUploader.csproj b/CloudWatchLogUploader/CloudWatchLogUploader.csproj index 67fb7c9..6218be5 100644 --- a/CloudWatchLogUploader/CloudWatchLogUploader.csproj +++ b/CloudWatchLogUploader/CloudWatchLogUploader.csproj @@ -11,6 +11,8 @@ CloudWatchLogUploader v4.5 512 + + AnyCPU @@ -32,6 +34,18 @@ 4 + + ..\packages\AWSSDK.CloudWatchLogs.3.3.1.3\lib\net45\AWSSDK.CloudWatchLogs.dll + True + + + ..\packages\AWSSDK.Core.3.3.6.1\lib\net45\AWSSDK.Core.dll + True + + + ..\packages\CommandLineParser.1.9.71\lib\net45\CommandLine.dll + True + @@ -42,13 +56,32 @@ + + + + + + + + + + + + + + + + This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. + + + + + + \ No newline at end of file diff --git a/CloudWatchLogUploader/CommandOptions.cs b/CloudWatchLogUploader/CommandOptions.cs new file mode 100644 index 0000000..57b0701 --- /dev/null +++ b/CloudWatchLogUploader/CommandOptions.cs @@ -0,0 +1,35 @@ +using CommandLine; +using CommandLine.Text; + +namespace CloudWatchLogUploader +{ + internal class CommandOptions + { + [Option('g', "logGroup", HelpText = "The log group you want to select the stream from, can end with '*' in which case the option to choose from all groups starting with this will be given")] + [ValueOption(0)] + public string LogGroup { get; set; } + + [Option('s', "logStream", HelpText = "The log stream you want to save, can end with '*' in which case the option to choose from all groups starting with this will be given")] + [ValueOption(1)] + public string LogStream { get; set; } + + [Option('o', "inputFile", HelpText = "The file to output the logs to")] + [ValueOption(2)] + public string InputFilePath { get; set; } + + [Option("overwrite", HelpText = "Deletes and recreates log stream if exists")] + public bool OverwriteStream { get; set; } + + [Option('d', "debug", HelpText = "print additional logs to console")] + public bool Debug { get; set; } + + [ParserState] + public IParserState ParserState { get; set; } + + [HelpOption] + public string GetUsage() + { + return HelpText.AutoBuild(this, (current) => HelpText.DefaultParsingErrorsHandler(this, current)); + } + } +} diff --git a/CloudWatchLogUploader/DebugLogger.cs b/CloudWatchLogUploader/DebugLogger.cs new file mode 100644 index 0000000..20afb10 --- /dev/null +++ b/CloudWatchLogUploader/DebugLogger.cs @@ -0,0 +1,87 @@ +using System; + +namespace CloudWatchLogUploader +{ + internal static class DebugLogger + { + private static bool _debug; + public static bool Debug + { + get { return _debug; } + set + { + if (value && !_debug) + { + WriteLine("debug mode active"); + } + _debug = value; + } + } + + public static void Write(string str) + { + if (_debug) + { + var oldcolor = Console.ForegroundColor; + Console.ForegroundColor = ConsoleColor.Cyan; + Console.Write(str); + Console.ForegroundColor = oldcolor; + } + } + + public static void Write(object obj) + { + if (_debug) + { + var oldcolor = Console.ForegroundColor; + Console.ForegroundColor = ConsoleColor.Cyan; + Console.Write(obj); + Console.ForegroundColor = oldcolor; + } + } + + public static void Write(string format, params object[] args) + { + if (_debug) + { + var oldcolor = Console.ForegroundColor; + Console.ForegroundColor = ConsoleColor.Cyan; + Console.Write(format, args); + Console.ForegroundColor = oldcolor; + } + } + + public static void WriteLine(string str) + { + if (_debug) + { + var oldcolor = Console.ForegroundColor; + Console.ForegroundColor = ConsoleColor.Cyan; + Console.WriteLine(str); + Console.ForegroundColor = oldcolor; + } + } + + public static void WriteLine(object obj) + { + if (_debug) + { + var oldcolor = Console.ForegroundColor; + Console.ForegroundColor = ConsoleColor.Cyan; + Console.WriteLine(obj); + Console.ForegroundColor = oldcolor; + } + } + + public static void WriteLine(string format, params object[] args) + { + if (_debug) + { + var oldcolor = Console.ForegroundColor; + Console.ForegroundColor = ConsoleColor.Cyan; + Console.WriteLine(format, args); + Console.ForegroundColor = oldcolor; + } + } + } +} diff --git a/CloudWatchLogUploader/FodyWeavers.xml b/CloudWatchLogUploader/FodyWeavers.xml new file mode 100644 index 0000000..2e6d4a7 --- /dev/null +++ b/CloudWatchLogUploader/FodyWeavers.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/CloudWatchLogUploader/LogGroupHelper.cs b/CloudWatchLogUploader/LogGroupHelper.cs new file mode 100644 index 0000000..04eb8df --- /dev/null +++ b/CloudWatchLogUploader/LogGroupHelper.cs @@ -0,0 +1,88 @@ +using Amazon.CloudWatchLogs; +using Amazon.CloudWatchLogs.Model; +using System; +using System.Collections.Generic; +using System.Linq; + +namespace CloudWatchLogUploader +{ + internal class LogGroupHelper : BaseHelper + { + public LogGroupHelper(AmazonCloudWatchLogsClient client) : base(client) + { + } + + public LogGroup GetLogGroup(string logGroup = null) + { + List allGroups = new List(); + DescribeLogGroupsResponse lgResponse = null; + do + { + DebugLogger.WriteLine("Getting logGroups..."); + lgResponse = client.DescribeLogGroups(new DescribeLogGroupsRequest { NextToken = (lgResponse != null ? lgResponse.NextToken : null) }); + allGroups.AddRange(lgResponse.LogGroups); + DebugLogger.WriteLine("Got logGroups, have {0}, {1} more pages", allGroups.Count, (!string.IsNullOrWhiteSpace(lgResponse.NextToken) ? "still" : "no")); + } while (!string.IsNullOrWhiteSpace(lgResponse.NextToken)); + + if (string.IsNullOrWhiteSpace(logGroup) || logGroup[logGroup.Length - 1] == '*') + { + if (!string.IsNullOrWhiteSpace(logGroup)) + { + if (logGroup.EndsWith("*")) + logGroup = logGroup.Substring(0, logGroup.Length - 1); + allGroups = allGroups.Where(x => x.LogGroupName.StartsWith(logGroup)).ToList(); + } + + for (int i = 0, len = allGroups.Count; i < len; ++i) + Console.WriteLine(i + ") " + allGroups[i].LogGroupName); + int num = ReadIntBetween("Choose log group (-1 to create one): ", -1, allGroups.Count - 1); + + if (num == -1) + { + if (logGroup[logGroup.Length - 1] == '*') + return CreateLogGroup(); + } + + Console.Clear(); + Console.WriteLine("You choose LogGroup: " + allGroups[num].LogGroupName); + return allGroups[num]; + } + + var lg = allGroups.FirstOrDefault(x => x.LogGroupName == logGroup); + if (lg == null) + { + Console.WriteLine("The log group '" + logGroup + "' does not exist."); + lg = CreateLogGroup(); + } + + Console.WriteLine("You choose LogGroup: " + lg.LogGroupName); + return lg; + } + + private LogGroup CreateLogGroup(string lgName = null) + { + if (string.IsNullOrWhiteSpace(lgName)) + { + lgName = GetLogGroupNameToCreate(); + } + else + { + Console.WriteLine("Do you want to create the log group [Y/N] (default: N): " + lgName); + if (!GetYesOrNo()) + { + lgName = GetLogGroupNameToCreate(); + } + } + + client.CreateLogGroup(new CreateLogGroupRequest(lgName)); + + return client.DescribeLogGroups(new DescribeLogGroupsRequest { LogGroupNamePrefix = lgName }).LogGroups.FirstOrDefault(); + } + + private string GetLogGroupNameToCreate() + { + Console.Write("Input log group name (Ctrl+C to abort): "); + return Console.ReadLine(); + } + } +} diff --git a/CloudWatchLogUploader/LogStreamHelper.cs b/CloudWatchLogUploader/LogStreamHelper.cs new file mode 100644 index 0000000..9c4557e --- /dev/null +++ b/CloudWatchLogUploader/LogStreamHelper.cs @@ -0,0 +1,125 @@ +using Amazon.CloudWatchLogs; +using Amazon.CloudWatchLogs.Model; +using System; +using System.Collections.Generic; +using System.Linq; +using System.IO; + +namespace CloudWatchLogUploader +{ + internal class LogStreamHelper : BaseHelper + { + public LogStreamHelper(AmazonCloudWatchLogsClient client) : base(client) + { + } + + public LogStream GetLogStream(LogGroup logGroup, string logStream = null) + { + List allStreams = new List(); + DescribeLogStreamsResponse lsResponse = null; + do + { + DebugLogger.WriteLine("Getting logStreams..."); + lsResponse = client.DescribeLogStreams(new DescribeLogStreamsRequest + { + NextToken = (lsResponse != null ? lsResponse.NextToken : null), + LogGroupName = logGroup.LogGroupName + }); + allStreams.AddRange(lsResponse.LogStreams); + DebugLogger.WriteLine("Got logStreams, have {0}, {1} more pages", allStreams.Count, (!string.IsNullOrWhiteSpace(lsResponse.NextToken) ? "still" : "no")); + } while (!string.IsNullOrWhiteSpace(lsResponse.NextToken)); + + if (string.IsNullOrWhiteSpace(logStream) || logStream[logStream.Length - 1] == '*') + { + if (!string.IsNullOrWhiteSpace(logStream)) + { + logStream = logStream.Substring(0, logStream.Length - 1); + allStreams = allStreams.Where(x => x.LogStreamName.StartsWith(logStream)).ToList(); + } + + allStreams = allStreams.OrderByDescending(x => x.CreationTime).ToList(); + + for (int i = 0, len = allStreams.Count; i < len; ++i) + Console.WriteLine(i + ") " + allStreams[i].LogStreamName); + int num = ReadIntBetween("Choose log stream: ", -1, allStreams.Count - 1); + + if (num == -1) + { + if (logStream[logStream.Length - 1] == '*') + return CreateLogStream(logGroup); + } + + Console.Clear(); + Console.WriteLine("You choose LogGroup: " + logGroup.LogGroupName + Environment.NewLine + "You choose LogStream: " + allStreams[num].LogStreamName); + return allStreams[num]; + } + + var ls = allStreams.FirstOrDefault(x => x.LogStreamName == logStream); + if (ls == null) + { + Console.WriteLine("The log stream '" + logGroup + "' does not exist."); + ls = CreateLogStream(logGroup); + } + + Console.WriteLine("You choose LogStream: " + ls.LogStreamName); + return ls; + } + + public void UploadLogs(LogGroup logGroup, LogStream logStream, bool overwriteStream, string inputFilePath = null) + { + string input = inputFilePath; + while (string.IsNullOrWhiteSpace(input)) + { + Console.WriteLine("Choose input file: "); + var possibleInput = Console.ReadLine(); + if (File.Exists(possibleInput) && !File.GetAttributes(possibleInput).HasFlag(FileAttributes.Directory)) + input = possibleInput; + else + Console.WriteLine(possibleInput + "doesn't exist or directory"); + } + + Console.Clear(); + Console.WriteLine(string.Format("Log stream: {1}{0}Log group: {2}{0}Overwrite stream: {3}{0}Input file: {4}{0}Do you want to start the upload? [Y/N] (default:N)", Environment.NewLine, logGroup.LogGroupName, logStream.LogStreamName, overwriteStream, input)); + if (!GetYesOrNo()) + return; + + using(var sr = new StreamReader(input)) + { + List events = new List(); + + while (!sr.EndOfStream) + { + events.Add(new InputLogEvent { Message = sr.ReadLine(), Timestamp = DateTime.UtcNow }); + } + + client.PutLogEvents(new PutLogEventsRequest(logGroup.LogGroupName, logStream.LogStreamName, events)); + } + } + + private LogStream CreateLogStream(LogGroup lg, string lsName = null) + { + if (string.IsNullOrWhiteSpace(lsName)) + { + lsName = GetLogStreamNameToCreate(); + } + else + { + Console.WriteLine("Do you want to create the log group [Y/N] (default: N): " + lsName); + if (!GetYesOrNo()) + { + lsName = GetLogStreamNameToCreate(); + } + } + + client.CreateLogStream(new CreateLogStreamRequest(lg.LogGroupName, lsName)); + + return client.DescribeLogStreams(new DescribeLogStreamsRequest { LogStreamNamePrefix = lsName, LogGroupName = lg.LogGroupName }).LogStreams.FirstOrDefault(); + } + + private string GetLogStreamNameToCreate() + { + Console.Write("Input log stream name (Ctrl+C to abort): "); + return Console.ReadLine(); + } + } +} diff --git a/CloudWatchLogUploader/Program.cs b/CloudWatchLogUploader/Program.cs index 87b473d..b8dd265 100644 --- a/CloudWatchLogUploader/Program.cs +++ b/CloudWatchLogUploader/Program.cs @@ -1,8 +1,5 @@ using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; +using Amazon.CloudWatchLogs; namespace CloudWatchLogUploader { @@ -10,6 +7,20 @@ namespace CloudWatchLogUploader { static void Main(string[] args) { + var opt = new CommandOptions(); + if (CommandLine.Parser.Default.ParseArguments(args, opt)) + { + DebugLogger.Debug = opt.Debug; + + var client = new AmazonCloudWatchLogsClient(); + var logGroup = new LogGroupHelper(client).GetLogGroup(opt.LogGroup); + var logStreamHelper = new LogStreamHelper(client); + var logStream = logStreamHelper.GetLogStream(logGroup, opt.LogStream); + logStreamHelper.UploadLogs(logGroup, logStream, opt.OverwriteStream, opt.InputFilePath); + + Console.Write("Upload complete, press any key to continue..."); + Console.ReadKey(); + } } } } diff --git a/CloudWatchLogUploader/packages.config b/CloudWatchLogUploader/packages.config new file mode 100644 index 0000000..5ba1e35 --- /dev/null +++ b/CloudWatchLogUploader/packages.config @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file