11 Commits

Author SHA1 Message Date
gardient
3942527292 some commit 2017-11-15 22:04:39 +02:00
Gardient
46687f004e adds build badge to readme 2016-11-17 12:17:59 +02:00
Gardient
ad2edf098d renames travis-ci yaml 2016-11-17 12:08:36 +02:00
Gardient
b7f06adce4 Adds travis-ci yaml 2016-11-17 12:06:54 +02:00
Gardient
de6becc208 adds debug logging 2016-11-15 14:48:41 +02:00
gardient
917624ad52 Adds license file 2016-11-10 14:04:19 +02:00
Gardient
e9c060cd0d #1 - fixes ignored command line argument 2016-11-10 13:47:37 +02:00
Gardient
acf3f8c0fe Updates README.md 2016-10-27 15:59:05 +03:00
Gardient
ea09bd6b19 Merge branch 'master' of github.com:gardient/CloudWatchLogDownloader 2016-10-27 15:53:58 +03:00
Gardient
2bfa977d99 Adds support for livestreaming logstreams 2016-10-27 15:51:04 +03:00
gardient
ddbfa25f8e Create README.md 2016-10-21 14:58:25 +03:00
8 changed files with 182 additions and 8 deletions

2
.travis.yml Normal file
View File

@@ -0,0 +1,2 @@
language: csharp
solution: CloudWatchLogDownloader.sln

View File

@@ -56,6 +56,7 @@
<Reference Include="System.Xml" /> <Reference Include="System.Xml" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Compile Include="DebugLogger.cs" />
<Compile Include="Models\CommandOptions.cs" /> <Compile Include="Models\CommandOptions.cs" />
<Compile Include="Program.cs" /> <Compile Include="Program.cs" />
<Compile Include="Properties\AssemblyInfo.cs" /> <Compile Include="Properties\AssemblyInfo.cs" />

View File

@@ -0,0 +1,87 @@
using System;
namespace CloudWatchLogDownloader
{
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;
}
}
}
}

View File

@@ -17,6 +17,12 @@ namespace CloudWatchLogDownloader.Models
[ValueOption(2)] [ValueOption(2)]
public string OutputFilePath { get; set; } public string OutputFilePath { get; set; }
[Option('l', "liveStream", HelpText="Keep pulling logs until Ctrl+C is applied")]
public bool LiveStream { get; set; }
[Option('d',"debug", HelpText = "print additional logs to console")]
public bool Debug { get; set; }
[ParserState] [ParserState]
public IParserState ParserState { get; set; } public IParserState ParserState { get; set; }

View File

@@ -16,10 +16,12 @@ namespace CloudWatchLogDownloader
var opt = new CommandOptions(); var opt = new CommandOptions();
if (CommandLine.Parser.Default.ParseArguments(args, opt)) if (CommandLine.Parser.Default.ParseArguments(args, opt))
{ {
DebugLogger.Debug = opt.Debug;
client = new AmazonCloudWatchLogsClient(); client = new AmazonCloudWatchLogsClient();
var logGroup = GetLogGroup(opt.LogGroup); var logGroup = GetLogGroup(opt.LogGroup);
var logStream = GetLogStream(logGroup, opt.LogStream); var logStream = GetLogStream(logGroup, opt.LogStream);
WriteLogToFile(logGroup, logStream, opt.OutputFilePath); WriteLogToFile(logGroup, logStream, opt.LiveStream, opt.OutputFilePath);
} }
} }
@@ -29,8 +31,10 @@ namespace CloudWatchLogDownloader
DescribeLogGroupsResponse lgResponse = null; DescribeLogGroupsResponse lgResponse = null;
do do
{ {
DebugLogger.WriteLine("Getting logGroups...");
lgResponse = client.DescribeLogGroups(new DescribeLogGroupsRequest { NextToken = (lgResponse != null ? lgResponse.NextToken : null) }); lgResponse = client.DescribeLogGroups(new DescribeLogGroupsRequest { NextToken = (lgResponse != null ? lgResponse.NextToken : null) });
allGroups.AddRange(lgResponse.LogGroups); 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)); } while (!string.IsNullOrWhiteSpace(lgResponse.NextToken));
if (string.IsNullOrWhiteSpace(logGroup) || logGroup[logGroup.Length - 1] == '*') if (string.IsNullOrWhiteSpace(logGroup) || logGroup[logGroup.Length - 1] == '*')
@@ -64,12 +68,14 @@ namespace CloudWatchLogDownloader
DescribeLogStreamsResponse lsResponse = null; DescribeLogStreamsResponse lsResponse = null;
do do
{ {
DebugLogger.WriteLine("Getting logStreams...");
lsResponse = client.DescribeLogStreams(new DescribeLogStreamsRequest lsResponse = client.DescribeLogStreams(new DescribeLogStreamsRequest
{ {
NextToken = (lsResponse != null ? lsResponse.NextToken : null), NextToken = (lsResponse != null ? lsResponse.NextToken : null),
LogGroupName = logGroup.LogGroupName LogGroupName = logGroup.LogGroupName
}); });
allStreams.AddRange(lsResponse.LogStreams); 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)); } while (!string.IsNullOrWhiteSpace(lsResponse.NextToken));
if (string.IsNullOrWhiteSpace(logStream) || logStream[logStream.Length - 1] == '*') if (string.IsNullOrWhiteSpace(logStream) || logStream[logStream.Length - 1] == '*')
@@ -80,7 +86,7 @@ namespace CloudWatchLogDownloader
allStreams = allStreams.Where(x => x.LogStreamName.StartsWith(logStream)).ToList(); allStreams = allStreams.Where(x => x.LogStreamName.StartsWith(logStream)).ToList();
} }
allStreams = allStreams.OrderBy(x => x.CreationTime).ToList(); allStreams = allStreams.OrderByDescending(x => x.CreationTime).ToList();
for (int i = 0, len = allStreams.Count; i < len; ++i) for (int i = 0, len = allStreams.Count; i < len; ++i)
Console.WriteLine(i + ") " + allStreams[i].LogStreamName); Console.WriteLine(i + ") " + allStreams[i].LogStreamName);
@@ -99,20 +105,34 @@ namespace CloudWatchLogDownloader
return ls; return ls;
} }
private static void WriteLogToFile(LogGroup logGroup, LogStream logStream, string outputFilePath = null) private static void WriteLogToFile(LogGroup logGroup, LogStream logStream, bool liveStream, string outputFilePath = null)
{
string output = null;
if (string.IsNullOrWhiteSpace(outputFilePath))
{ {
Console.WriteLine("Choose Output file [logs/" + logStream.LogStreamName + ".log]: "); Console.WriteLine("Choose Output file [logs/" + logStream.LogStreamName + ".log]: ");
var output = Console.ReadLine(); output = Console.ReadLine();
if (string.IsNullOrWhiteSpace(output)) if (string.IsNullOrWhiteSpace(output))
output = "logs/" + logStream.LogStreamName + ".log"; output = "logs/" + logStream.LogStreamName + ".log";
}
else
{
output = outputFilePath;
}
if (!Directory.GetParent(output).Exists) if (!Directory.GetParent(output).Exists)
Directory.CreateDirectory(Directory.GetParent(output).FullName); Directory.CreateDirectory(Directory.GetParent(output).FullName);
Console.WriteLine("Downloading log into " + output);
bool lsMessage = !liveStream;
using (StreamWriter sw = new StreamWriter(output)) using (StreamWriter sw = new StreamWriter(output))
{ {
GetLogEventsResponse leResponse = null; GetLogEventsResponse leResponse = null;
do do
{ {
DebugLogger.WriteLine("Getting events...");
leResponse = client.GetLogEvents(new GetLogEventsRequest leResponse = client.GetLogEvents(new GetLogEventsRequest
{ {
LogGroupName = logGroup.LogGroupName, LogGroupName = logGroup.LogGroupName,
@@ -120,12 +140,23 @@ namespace CloudWatchLogDownloader
StartFromHead = true, StartFromHead = true,
NextToken = (leResponse != null ? leResponse.NextForwardToken : null) NextToken = (leResponse != null ? leResponse.NextForwardToken : null)
}); });
DebugLogger.WriteLine("Got {0} events", leResponse.Events.Count);
foreach (var ev in leResponse.Events) foreach (var ev in leResponse.Events)
sw.WriteLine(ev.Message); sw.WriteLine(ev.Message);
sw.Flush(); sw.Flush();
} while (leResponse.NextForwardToken != null && leResponse.Events.Any());
if (!leResponse.Events.Any() && !lsMessage && liveStream)
{
lsMessage = true;
ConsoleColor oldcolor = Console.ForegroundColor;
Console.ForegroundColor = ConsoleColor.Yellow;
Console.WriteLine("Now streaming live from lg: " + logGroup.LogGroupName + " ls: " + logStream.LogStreamName + " into " + output);
Console.ForegroundColor = oldcolor;
Console.WriteLine("{0}{0}Press CTRL+C to stop...", Environment.NewLine);
}
} while ((leResponse.NextForwardToken != null && leResponse.Events.Any()) || liveStream);
} }
} }

21
LICENSE Normal file
View File

@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2016 gardient
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

26
README.md Normal file
View File

@@ -0,0 +1,26 @@
# CloudWatchLogDownloader
Download full logs from AWS CloudWatch
[![Build Status](https://travis-ci.org/gardient/CloudWatchLogDownloader.svg)](https://travis-ci.org/gardient/CloudWatchLogDownloader)
## Who is it for?
For idiots like me who just want a text dump of the cloud watch log without going through S3
## Why .NET?
Because I was working with the .NET AWSSDK when writing this.
## Why not .NET CORE?
Because the AWSSDK.CloudWatchLogs nuget package doesn't support it. (As of writing this README)
## Usage
If you're still reading this means you want to use this abomination... Good.
### Command line params
|short|long|Description|
|-----|----|-----------|
|-g|--logGroup|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|
|-s|--logStream|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|
|-o|--outputFile|The file to output the logs to.|
|-l|--liveStream|After reaching the newest log keep polling until ctrl+c is pressed|
If any of the above are not specified the program will prompt for them

BIN
asd.txt Normal file

Binary file not shown.