diff --git a/RelationalAI.Test/DatabaseTest.cs b/RelationalAI.Test/DatabaseTest.cs index d2d0b2d..812ba37 100644 --- a/RelationalAI.Test/DatabaseTest.cs +++ b/RelationalAI.Test/DatabaseTest.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.Threading.Tasks; using Xunit; +using Xunit.Abstractions; namespace RelationalAI.Test { @@ -9,18 +10,20 @@ namespace RelationalAI.Test public class DatabaseTests : UnitTest { private readonly EngineFixture engineFixture; + private readonly ITestOutputHelper outputHelper; public static string Uuid = Guid.NewGuid().ToString(); public static string Dbname = $"csharp-sdk-{Uuid}"; - public DatabaseTests(EngineFixture fixture) + public DatabaseTests(EngineFixture fixture, ITestOutputHelper output) { + outputHelper = output; engineFixture = fixture; } [Fact] public async Task DatabaseTest() { - var client = CreateClient(); + var client = CreateClient(outputHelper); await engineFixture.CreateEngineWaitAsync(); await Assert.ThrowsAsync(async () => await client.DeleteDatabaseAsync(Dbname)); @@ -77,7 +80,7 @@ await Assert.ThrowsAsync(() => [Fact] public async Task DatabaseCloneTest() { - var client = CreateClient(); + var client = CreateClient(outputHelper); await engineFixture.CreateEngineWaitAsync(); await Assert.ThrowsAsync(async () => await client.DeleteDatabaseAsync(Dbname)); @@ -145,7 +148,7 @@ public async Task DatabaseCloneTest() public override async Task DisposeAsync() { - var client = CreateClient(); + var client = CreateClient(outputHelper); try { diff --git a/RelationalAI.Test/EngineTest.cs b/RelationalAI.Test/EngineTest.cs index 29ec3c2..06680fc 100644 --- a/RelationalAI.Test/EngineTest.cs +++ b/RelationalAI.Test/EngineTest.cs @@ -1,24 +1,26 @@ using System; using System.Threading.Tasks; using Xunit; +using Xunit.Abstractions; namespace RelationalAI.Test { [Collection("RelationalAI.Test")] public class EngineTests : UnitTest { - + private readonly ITestOutputHelper outputHelper; private readonly EngineFixture engineFixture; - public EngineTests(EngineFixture fixture) + public EngineTests(EngineFixture fixture, ITestOutputHelper output) { + outputHelper = output; engineFixture = fixture; } [Fact] public async Task EngineTest() { - var client = CreateClient(); + var client = CreateClient(outputHelper); await engineFixture.CreateEngineWaitAsync(); diff --git a/RelationalAI.Test/ExecuteAsync.cs b/RelationalAI.Test/ExecuteAsync.cs index 79981c5..121cded 100644 --- a/RelationalAI.Test/ExecuteAsync.cs +++ b/RelationalAI.Test/ExecuteAsync.cs @@ -4,6 +4,7 @@ using Relationalai.Protocol; using Xunit; using System.Threading.Tasks; +using Xunit.Abstractions; namespace RelationalAI.Test { @@ -13,17 +14,19 @@ public class ExecuteAsyncTests : UnitTest public static string Uuid = Guid.NewGuid().ToString(); public static string Dbname = $"csharp-sdk-{Uuid}"; + private readonly ITestOutputHelper outputHelper; private readonly EngineFixture engineFixture; - public ExecuteAsyncTests(EngineFixture fixture) + public ExecuteAsyncTests(EngineFixture fixture, ITestOutputHelper output) { + outputHelper = output; engineFixture = fixture; } [Fact] public async Task ExecuteAsyncTest() { - var client = CreateClient(); + var client = CreateClient(outputHelper); await engineFixture.CreateEngineWaitAsync(); await client.CreateDatabaseAsync(Dbname, engineFixture.Engine.Name); @@ -50,7 +53,7 @@ public async Task ExecuteAsyncTest() public override async Task DisposeAsync() { - var client = CreateClient(); + var client = CreateClient(outputHelper); try { diff --git a/RelationalAI.Test/ExecuteV1Test.cs b/RelationalAI.Test/ExecuteV1Test.cs index 5da2a94..a5d28ea 100644 --- a/RelationalAI.Test/ExecuteV1Test.cs +++ b/RelationalAI.Test/ExecuteV1Test.cs @@ -1,6 +1,7 @@ using System; using System.Threading.Tasks; using Xunit; +using Xunit.Abstractions; namespace RelationalAI.Test { @@ -9,17 +10,19 @@ public class ExecuteTests : UnitTest { public static string Uuid = Guid.NewGuid().ToString(); public static string Dbname = $"csharp-sdk-{Uuid}"; + private readonly ITestOutputHelper outputHelper; private readonly EngineFixture engineFixture; - public ExecuteTests(EngineFixture fixture) + public ExecuteTests(EngineFixture fixture, ITestOutputHelper output) { + outputHelper = output; engineFixture = fixture; } [Fact] public async Task ExecuteV1Test() { - var client = CreateClient(); + var client = CreateClient(outputHelper); await engineFixture.CreateEngineWaitAsync(); await client.CreateDatabaseAsync(Dbname, engineFixture.Engine.Name); @@ -49,7 +52,7 @@ public async Task ExecuteV1Test() public override async Task DisposeAsync() { - var client = CreateClient(); + var client = CreateClient(outputHelper); try { diff --git a/RelationalAI.Test/LoadCsvTest.cs b/RelationalAI.Test/LoadCsvTest.cs index 267a6c2..815f603 100644 --- a/RelationalAI.Test/LoadCsvTest.cs +++ b/RelationalAI.Test/LoadCsvTest.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.Threading.Tasks; using Xunit; +using Xunit.Abstractions; namespace RelationalAI.Test { @@ -18,17 +19,19 @@ public class LoadCsvTests : UnitTest "\"cosmopolitan\",4,11.00,\"2020-03-03\"\n" + "\"bellini\",3,12.25,\"2020-04-04\"\n"; + private readonly ITestOutputHelper outputHelper; private readonly EngineFixture engineFixture; - public LoadCsvTests(EngineFixture fixture) + public LoadCsvTests(EngineFixture fixture, ITestOutputHelper output) { + outputHelper = output; engineFixture = fixture; } [Fact] public async Task LoadCsvtTest() { - var client = CreateClient(); + var client = CreateClient(outputHelper); await engineFixture.CreateEngineWaitAsync(); await client.CreateDatabaseAsync(Dbname, engineFixture.Engine.Name); @@ -98,7 +101,7 @@ public async Task LoadCsvtTest() [Fact] public async Task LoadCsvNoHeaderTest() { - var client = CreateClient(); + var client = CreateClient(outputHelper); await engineFixture.CreateEngineWaitAsync(); await client.CreateDatabaseAsync(Dbname, engineFixture.Engine.Name); @@ -171,7 +174,7 @@ public async Task LoadCsvNoHeaderTest() [Fact] public async Task LoadCsvAltSyntaxTest() { - var client = CreateClient(); + var client = CreateClient(outputHelper); await engineFixture.CreateEngineWaitAsync(); await client.CreateDatabaseAsync(Dbname, engineFixture.Engine.Name); @@ -236,7 +239,7 @@ public async Task LoadCsvAltSyntaxTest() [Fact] public async Task LoadCsvWithSchemaTest() { - var client = CreateClient(); + var client = CreateClient(outputHelper); await engineFixture.CreateEngineWaitAsync(); await client.CreateDatabaseAsync(Dbname, engineFixture.Engine.Name); @@ -316,7 +319,7 @@ public async Task LoadCsvWithSchemaTest() public override async Task DisposeAsync() { - var client = CreateClient(); + var client = CreateClient(outputHelper); try { await client.DeleteDatabaseAsync(Dbname); diff --git a/RelationalAI.Test/LoadJsonTest.cs b/RelationalAI.Test/LoadJsonTest.cs index 5016e1f..2a1eaa7 100644 --- a/RelationalAI.Test/LoadJsonTest.cs +++ b/RelationalAI.Test/LoadJsonTest.cs @@ -1,6 +1,7 @@ using System; using System.Threading.Tasks; using Xunit; +using Xunit.Abstractions; namespace RelationalAI.Test { @@ -15,17 +16,19 @@ public class LoadJsonTests : UnitTest "\"height\":null,\n" + "\"pets\":[\"dog\",\"rabbit\"]}"; + private readonly ITestOutputHelper outputHelper; private readonly EngineFixture engineFixture; - public LoadJsonTests(EngineFixture fixture) + public LoadJsonTests(EngineFixture fixture, ITestOutputHelper output) { + outputHelper = output; engineFixture = fixture; } [Fact] public async Task LoadJsontTest() { - var client = CreateClient(); + var client = CreateClient(outputHelper); await engineFixture.CreateEngineWaitAsync(); await client.CreateDatabaseAsync(Dbname, engineFixture.Engine.Name); @@ -60,7 +63,7 @@ public async Task LoadJsontTest() public override async Task DisposeAsync() { - var client = CreateClient(); + var client = CreateClient(outputHelper); try { diff --git a/RelationalAI.Test/ModelsTest.cs b/RelationalAI.Test/ModelsTest.cs index 6ba19cd..3e1935e 100644 --- a/RelationalAI.Test/ModelsTest.cs +++ b/RelationalAI.Test/ModelsTest.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.Threading.Tasks; using Xunit; +using Xunit.Abstractions; namespace RelationalAI.Test { @@ -12,17 +13,19 @@ public class ModelsTests : UnitTest public static string Dbname = $"csharp-sdk-{Uuid}"; private readonly Dictionary TestModel = new Dictionary { { "test_model", "def R = \"hello\", \"world\"" } }; + private readonly ITestOutputHelper outputHelper; private readonly EngineFixture engineFixture; - public ModelsTests(EngineFixture fixture) + public ModelsTests(EngineFixture fixture, ITestOutputHelper output) { + outputHelper = output; engineFixture = fixture; } [Fact] public async Task ModelsTest() { - var client = CreateClient(); + var client = CreateClient(outputHelper); await engineFixture.CreateEngineWaitAsync(); await client.CreateDatabaseAsync(Dbname, engineFixture.Engine.Name); @@ -51,7 +54,7 @@ public async Task ModelsTest() public override async Task DisposeAsync() { - var client = CreateClient(); + var client = CreateClient(outputHelper); try { diff --git a/RelationalAI.Test/OAuthClientTest.cs b/RelationalAI.Test/OAuthClientTest.cs index cec630b..406f78c 100644 --- a/RelationalAI.Test/OAuthClientTest.cs +++ b/RelationalAI.Test/OAuthClientTest.cs @@ -1,6 +1,7 @@ using System; using System.Threading.Tasks; using Xunit; +using Xunit.Abstractions; namespace RelationalAI.Test { @@ -8,6 +9,12 @@ public class OAuthClientTests : UnitTest { public static string Uuid = Guid.NewGuid().ToString(); public static string OAuthClientName = $"csharp-sdk-{Uuid}"; + private readonly ITestOutputHelper outputHelper; + + public OAuthClientTests(ITestOutputHelper output) + { + outputHelper = output; + } [Fact] public async Task OAuthClientTest() diff --git a/RelationalAI.Test/RAITestTraceListener.cs b/RelationalAI.Test/RAITestTraceListener.cs new file mode 100644 index 0000000..fd6edd9 --- /dev/null +++ b/RelationalAI.Test/RAITestTraceListener.cs @@ -0,0 +1,27 @@ +using System.Diagnostics; +using Xunit.Abstractions; + +namespace RelationalAI.Test +{ + public class RAITestTraceListener : TraceListener + { + private readonly ITestOutputHelper testOutputHelper; + + public RAITestTraceListener(ITestOutputHelper testOutputHelper) + { + this.testOutputHelper = testOutputHelper; + } + public override void Write(string message) + { + // ITestOutputHelper has no Write function + // using WriteLine for the moment until we figure + // out a better way to this + testOutputHelper.WriteLine(message); + } + + public override void WriteLine(string message) + { + testOutputHelper.WriteLine(message); + } + } +} \ No newline at end of file diff --git a/RelationalAI.Test/UnitTest.cs b/RelationalAI.Test/UnitTest.cs index 143f918..b9a16b3 100644 --- a/RelationalAI.Test/UnitTest.cs +++ b/RelationalAI.Test/UnitTest.cs @@ -1,17 +1,19 @@ using System; using System.Collections.Generic; +using System.Diagnostics; using System.IO; using System.Linq; using System.Text; using System.Threading.Tasks; using Newtonsoft.Json; using Xunit; +using Xunit.Abstractions; namespace RelationalAI.Test { public class UnitTest : IAsyncLifetime { - public Client CreateClient() + public Client CreateClient(ITestOutputHelper testOutputHelper = null) { Dictionary config; @@ -52,6 +54,15 @@ public Client CreateClient() { httpClient.DefaultRequestHeaders.Add(header.Key, header.Value); } + + // Logging configuration + if (testOutputHelper != null) + { + var logger = testClient.Logger as RAITraceSourceLogger; + logger.AddListener(new RAITestTraceListener(testOutputHelper)); + logger.SwitchLogLevel(TraceEventType.Verbose); + } + return testClient; } diff --git a/RelationalAI.Test/UserTest.cs b/RelationalAI.Test/UserTest.cs index 0734e05..38d65a9 100644 --- a/RelationalAI.Test/UserTest.cs +++ b/RelationalAI.Test/UserTest.cs @@ -3,6 +3,7 @@ using System.Linq; using System.Threading.Tasks; using Xunit; +using Xunit.Abstractions; namespace RelationalAI.Test { @@ -10,11 +11,17 @@ public class UserTest : UnitTest { public static string Uuid = Guid.NewGuid().ToString(); public static string UserEmail = $"csharp-sdk-{Uuid}@example.com"; + private readonly ITestOutputHelper outputHelper; + + public UserTest(ITestOutputHelper output) + { + outputHelper = output; + } [Fact] public async Task TestUser() { - var client = CreateClient(); + var client = CreateClient(outputHelper); await Assert.ThrowsAsync(async () => await client.FindUserAsync(UserEmail)); @@ -59,7 +66,7 @@ public async Task TestUser() public override async Task DisposeAsync() { - var client = CreateClient(); + var client = CreateClient(outputHelper); try { diff --git a/RelationalAI/Client.cs b/RelationalAI/Client.cs index 31a130f..a2dc113 100644 --- a/RelationalAI/Client.cs +++ b/RelationalAI/Client.cs @@ -37,11 +37,13 @@ public class Client private const string PathOAuthClients = "/oauth-clients"; private readonly Rest _rest; private readonly Context _context; + private IRAILogger _logger; public Client(Context context) { _context = context; - _rest = new Rest(context); + _logger = new RAITraceSourceLogger("RAI"); + _rest = new Rest(context, _logger); } public HttpClient HttpClient @@ -50,6 +52,8 @@ public HttpClient HttpClient set { _rest.HttpClient = value; } } + public IRAILogger Logger => _logger; + public Task CreateDatabaseAsync(string database, string engine) { return CreateDatabaseAsync(database, engine, false); @@ -57,6 +61,7 @@ public Task CreateDatabaseAsync(string database, string engine) public async Task CreateDatabaseAsync(string database, string engine, bool overwrite) { + _logger.Debug($"creating database {database}"); var mode = CreateMode(null, overwrite); var transaction = new Transaction(_context.Region, database, engine, mode); await _rest.PostAsync(MakeUrl(PathTransaction), transaction.Payload(null), null, transaction.QueryParams()); @@ -111,6 +116,7 @@ public async Task DeleteDatabaseAsync(string database) public async Task CreateEngineAsync(string engine, string size = "XS") { + _logger.Debug($"creating engine {engine} with size {size}"); var data = new Dictionary { { "region", _context.Region }, @@ -532,6 +538,7 @@ public async Task ExecuteAsync( if (rsp is string s) { var txn = Json.Deserialize(s); + _logger.Debug($"transaction id {txn.Id}"); return new TransactionAsyncResult(txn, new List(), null, new List()); } @@ -741,6 +748,7 @@ private TransactionAsyncResult ReadTransactionAsyncResults(List.Deserialize(_rest.ReadString(transaction.Data)); + _logger.Debug($"transaction id {transactionResult.Id}"); var metadataProto = _rest.ReadMetadataProtobuf(metadata.Data); List problemsResult = null; diff --git a/RelationalAI/IRAILogger.cs b/RelationalAI/IRAILogger.cs new file mode 100644 index 0000000..270eac8 --- /dev/null +++ b/RelationalAI/IRAILogger.cs @@ -0,0 +1,13 @@ +namespace RelationalAI +{ + // an interface to for loggers implementations + public interface IRAILogger + { + void Debug(string message); + void Info(string message); + void Warning(string message); + void Error(string message); + void Fatal(string message); + void Trace(string message); + } +} diff --git a/RelationalAI/RAITraceSourceLogger.cs b/RelationalAI/RAITraceSourceLogger.cs new file mode 100644 index 0000000..a9809f4 --- /dev/null +++ b/RelationalAI/RAITraceSourceLogger.cs @@ -0,0 +1,62 @@ +using System.Diagnostics; + +namespace RelationalAI +{ + public class RAITraceSourceLogger : IRAILogger + { + private readonly int _loggerId; + private readonly TraceSource _traceSource; + + public RAITraceSourceLogger(string name, int id = 100) + { + _traceSource = new TraceSource(name, SourceLevels.All); + _loggerId = id; + } + + public void Debug(string message) + { + _traceSource.TraceEvent(TraceEventType.Verbose, _loggerId, message); + _traceSource.Flush(); + } + + public void Error(string message) + { + _traceSource.TraceEvent(TraceEventType.Error, _loggerId, message); + _traceSource.Flush(); + } + + public void Fatal(string message) + { + _traceSource.TraceEvent(TraceEventType.Critical, _loggerId, message); + _traceSource.Flush(); + } + + public void Info(string message) + { + _traceSource.TraceEvent(TraceEventType.Information, _loggerId, message); + _traceSource.Flush(); + } + + public void Trace(string message) + { + _traceSource.TraceEvent(TraceEventType.Verbose, _loggerId, message); + _traceSource.Flush(); + } + + public void Warning(string message) + { + _traceSource.TraceEvent(TraceEventType.Warning, _loggerId, message); + _traceSource.Flush(); + } + + public int AddListener(TraceListener listener) + { + return _traceSource.Listeners.Add(listener); + } + + public bool SwitchLogLevel(TraceEventType eventType) + { + return _traceSource.Switch.ShouldTrace(eventType); + } + } +} diff --git a/RelationalAI/Rest.cs b/RelationalAI/Rest.cs index b0114da..689db1c 100644 --- a/RelationalAI/Rest.cs +++ b/RelationalAI/Rest.cs @@ -37,11 +37,13 @@ public class Rest private const string RequestIdHeaderName = "X-Request-ID"; private readonly Context _context; + private readonly IRAILogger _logger; - public Rest(Context context) + public Rest(Context context, IRAILogger logger) { _context = context; HttpClient = new HttpClient(); + _logger = logger; } public HttpClient HttpClient { get; set; }