From dfa110b7cb520dcd436e2f50c03041e0b0a678e6 Mon Sep 17 00:00:00 2001 From: fw2568 Date: Fri, 30 Nov 2018 20:39:40 +0100 Subject: [PATCH] added logging feature (#8) --- src/Contiva.SAP.NWRfc.Abstractions/ILogger.cs | 20 ++++ .../IRfcRuntime.cs | 1 + src/Contiva.SAP.NWRfc.Core/Connection.cs | 5 +- .../AssemblyInfo.cpp | Bin 1628 -> 1628 bytes .../HandleWrappers.h | 14 +++ src/Contiva.SAP.NwRfc.Runtime/RfcRuntime.cs | 70 ++++++++++++- test/SAPSystemTests/Program.cs | 2 +- test/SAPSystemTests/SimpleConsoleLogger.cs | 97 ++++++++++++++++++ 8 files changed, 200 insertions(+), 9 deletions(-) create mode 100644 src/Contiva.SAP.NWRfc.Abstractions/ILogger.cs create mode 100644 test/SAPSystemTests/SimpleConsoleLogger.cs diff --git a/src/Contiva.SAP.NWRfc.Abstractions/ILogger.cs b/src/Contiva.SAP.NWRfc.Abstractions/ILogger.cs new file mode 100644 index 00000000..9988364b --- /dev/null +++ b/src/Contiva.SAP.NWRfc.Abstractions/ILogger.cs @@ -0,0 +1,20 @@ +using System; + +namespace Contiva.SAP.NWRfc +{ + public interface ILogger + { + void LogException(Exception exception, string message); + void LogException(Exception exception); + void LogTrace(string message, object data); + void LogError(string message, object data); + + void LogDebug(string message, object data); + + void LogTrace(string message); + void LogDebug(string message); + void LogError(string message); + + + } +} \ No newline at end of file diff --git a/src/Contiva.SAP.NWRfc.Abstractions/IRfcRuntime.cs b/src/Contiva.SAP.NWRfc.Abstractions/IRfcRuntime.cs index df2edfb1..d0f7d400 100644 --- a/src/Contiva.SAP.NWRfc.Abstractions/IRfcRuntime.cs +++ b/src/Contiva.SAP.NWRfc.Abstractions/IRfcRuntime.cs @@ -44,5 +44,6 @@ public interface IRfcRuntime Either SetTimeString(IDataContainerHandle containerHandle, string name, string value); Either GetTimeString(IDataContainerHandle containerHandle, string name); + Option Logger { get; } } } \ No newline at end of file diff --git a/src/Contiva.SAP.NWRfc.Core/Connection.cs b/src/Contiva.SAP.NWRfc.Core/Connection.cs index f234d6e8..5cebc36e 100644 --- a/src/Contiva.SAP.NWRfc.Core/Connection.cs +++ b/src/Contiva.SAP.NWRfc.Core/Connection.cs @@ -19,8 +19,6 @@ public Connection( _stateAgent = Agent.Start>( connectionHandle, (handle, msg) => { - Console.WriteLine($"Agent: {System.Threading.Thread.CurrentThread.ManagedThreadId}"); - if (handle == null) return (null, new RfcErrorInfo(RfcRc.RFC_INVALID_HANDLE, RfcErrorGroup.EXTERNAL_RUNTIME_FAILURE, @@ -64,7 +62,7 @@ public Connection( } catch (Exception ex) { - Console.WriteLine(ex); + rfcRuntime.Logger.IfSome(l => l.LogException(ex)); } throw new InvalidOperationException(); @@ -76,6 +74,7 @@ public static Task> Create(IDictionary (IConnection) new Connection(handle, runtime)).AsTask(); } + public Task> CommitAndWait() { return CreateFunction("BAPI_TRANSACTION_COMMIT") diff --git a/src/Contiva.SAP.NWRfc.Native.clr/AssemblyInfo.cpp b/src/Contiva.SAP.NWRfc.Native.clr/AssemblyInfo.cpp index 434bfdfd038cd3e41c09ac2ff30893a8ac5c20b3..442d9c19471931c5d84f0cb184f6b0cf2ed74022 100644 GIT binary patch delta 19 bcmcb^bBAZcHdbb12BpcrSyd2BpcrSyd //for std::stringstream +#include //for std::string + using namespace System; @@ -48,6 +51,17 @@ namespace Contiva { protected: virtual void DestroyHandle(T handle) abstract; + + public: + virtual String^ ToString() override + { + const void * address = static_cast(Handle); + std::stringstream ss; + ss << address; + std::string name = ss.str(); + + return gcnew String(name.c_str()); + } }; template diff --git a/src/Contiva.SAP.NwRfc.Runtime/RfcRuntime.cs b/src/Contiva.SAP.NwRfc.Runtime/RfcRuntime.cs index 3e88f7bf..053422c5 100644 --- a/src/Contiva.SAP.NwRfc.Runtime/RfcRuntime.cs +++ b/src/Contiva.SAP.NwRfc.Runtime/RfcRuntime.cs @@ -8,32 +8,60 @@ namespace Contiva.SAP.NWRfc { public class RfcRuntime : IRfcRuntime { + public RfcRuntime(ILogger logger = null) + { + Logger = logger == null ? Option.None : Option.Some(logger); + } - private static Either ResultOrError(TResult result, RfcErrorInfo errorInfo) + private Either ResultOrError(TResult result, RfcErrorInfo errorInfo, bool logAsError = false) { if (result == null) + { + Logger.IfSome(l => + { + if(logAsError) + l.LogError("received error from rfc call", errorInfo); + else + l.LogDebug("received error from rfc call", errorInfo); + }); return errorInfo; + } + + Logger.IfSome(l => l.LogTrace("received result value from rfc call", result)); return result; } - private static Either ResultOrError(TResult result, RfcRc rc, RfcErrorInfo errorInfo) + private Either ResultOrError(TResult result, RfcRc rc, RfcErrorInfo errorInfo) { if (rc != RfcRc.RFC_OK) + { + Logger.IfSome(l => l.LogDebug("received error from rfc call", errorInfo)); return errorInfo; + } + Logger.IfSome(l => l.LogTrace("received result value from rfc call", result)); return result; } public Either OpenConnection(IDictionary connectionParams) { + var loggedParams = new Dictionary(connectionParams); + + // ReSharper disable StringLiteralTypo + if (loggedParams.ContainsKey("passwd")) + loggedParams["passwd"] = "XXXX"; + // ReSharper restore StringLiteralTypo + + Logger.IfSome(l => l.LogTrace("Opening connection", loggedParams)); IConnectionHandle handle = NativeApi.OpenConnection(connectionParams, out var errorInfo); - return ResultOrError(handle, errorInfo); + return ResultOrError(handle, errorInfo, true); } public Either GetFunctionDescription(IConnectionHandle connectionHandle, string functionName) { + Logger.IfSome(l => l.LogTrace("reading function description by function name", functionName)); IFunctionDescriptionHandle handle = NativeApi.GetFunctionDescription(connectionHandle as ConnectionHandle, functionName, out var errorInfo); return ResultOrError(handle, errorInfo); @@ -41,6 +69,7 @@ public Either GetFunctionDescription(I public Either GetFunctionDescription(IFunctionHandle functionHandle) { + Logger.IfSome(l => l.LogTrace("reading function description by function handle", functionHandle)); IFunctionDescriptionHandle handle = NativeApi.GetFunctionDescription(functionHandle as FunctionHandle, out var errorInfo); return ResultOrError(handle, errorInfo); @@ -48,6 +77,7 @@ public Either GetFunctionDescription(I public Either GetTypeDescription(IDataContainerHandle dataContainer) { + Logger.IfSome(l => l.LogTrace("reading type description by container handle", dataContainer)); ITypeDescriptionHandle handle = NativeApi.GetTypeDescription(dataContainer as Native.IDataContainerHandle, out var errorInfo); return ResultOrError(handle, errorInfo); @@ -55,6 +85,7 @@ public Either GetTypeDescription(IDataCont public Either GetFunctionName(IFunctionDescriptionHandle descriptionHandle) { + Logger.IfSome(l => l.LogTrace("reading function name by description handle", descriptionHandle)); var rc = NativeApi.GetFunctionName(descriptionHandle as FunctionDescriptionHandle, out var result, out var errorInfo); return ResultOrError(result, rc, errorInfo); @@ -62,6 +93,7 @@ public Either GetFunctionName(IFunctionDescriptionHandle d public Either GetTypeFieldCount(ITypeDescriptionHandle descriptionHandle) { + Logger.IfSome(l => l.LogTrace("reading field count by type description handle", descriptionHandle)); var rc = NativeApi.GetTypeFieldCount(descriptionHandle as TypeDescriptionHandle, out var result, out var errorInfo); return ResultOrError(result, rc, errorInfo); @@ -70,6 +102,7 @@ public Either GetTypeFieldCount(ITypeDescriptionHandle descri public Either GetTypeFieldDescription(ITypeDescriptionHandle descriptionHandle, int index) { + Logger.IfSome(l => l.LogTrace("reading field description by type description handle and index", new { descriptionHandle, index })); var rc = NativeApi.GetTypeFieldDescription(descriptionHandle as TypeDescriptionHandle, index, out var result, out var errorInfo); return ResultOrError(result, rc, errorInfo); @@ -78,7 +111,7 @@ public Either GetTypeFieldDescription(ITypeDescripti public Either GetTypeFieldDescription(ITypeDescriptionHandle descriptionHandle, string name) { - + Logger.IfSome(l => l.LogTrace("reading field description by type description handle and name", new { descriptionHandle, name })); var rc = NativeApi.GetTypeFieldDescription(descriptionHandle as TypeDescriptionHandle, name, out var result, out var errorInfo); return ResultOrError(result, rc, errorInfo); @@ -86,6 +119,7 @@ public Either GetTypeFieldDescription(ITypeDescripti public Either CreateFunction(IFunctionDescriptionHandle descriptionHandle) { + Logger.IfSome(l => l.LogTrace("creating function by function description handle", descriptionHandle)); IFunctionHandle handle = NativeApi.CreateFunction(descriptionHandle as FunctionDescriptionHandle, out var errorInfo); return ResultOrError(handle, errorInfo); @@ -93,6 +127,7 @@ public Either CreateFunction(IFunctionDescription public Either GetFunctionParameterCount(IFunctionDescriptionHandle descriptionHandle) { + Logger.IfSome(l => l.LogTrace("reading function parameter count by function description handle", descriptionHandle)); var rc = NativeApi.GetFunctionParameterCount(descriptionHandle as FunctionDescriptionHandle, out var result, out var errorInfo); return ResultOrError(result, rc, errorInfo); @@ -101,6 +136,7 @@ public Either GetFunctionParameterCount(IFunctionDescriptionH public Either GetFunctionParameterDescription( IFunctionDescriptionHandle descriptionHandle, int index) { + Logger.IfSome(l => l.LogTrace("reading function parameter description by function description handle and index", new { descriptionHandle, index })); var rc = NativeApi.GetFunctionParameterDescription(descriptionHandle as FunctionDescriptionHandle, index, out var result, out var errorInfo); return ResultOrError(result, rc, errorInfo); @@ -109,6 +145,7 @@ public Either GetFunctionParameterDescription( public Either GetFunctionParameterDescription( IFunctionDescriptionHandle descriptionHandle, string name) { + Logger.IfSome(l => l.LogTrace("reading function parameter description by function description handle and name", new { descriptionHandle, name })); var rc = NativeApi.GetFunctionParameterDescription(descriptionHandle as FunctionDescriptionHandle, name, out var result, out var errorInfo); return ResultOrError(result, rc, errorInfo); @@ -116,6 +153,7 @@ public Either GetFunctionParameterDescription( public Either Invoke(IConnectionHandle connectionHandle, IFunctionHandle functionHandle) { + Logger.IfSome(l => l.LogTrace("Invoking function", new { connectionHandle, functionHandle })); var rc = NativeApi.Invoke(connectionHandle as ConnectionHandle, functionHandle as FunctionHandle, out var errorInfo); return ResultOrError(Unit.Default, rc, errorInfo); @@ -123,6 +161,7 @@ public Either Invoke(IConnectionHandle connectionHandle, IFu public Either GetStructure(IDataContainerHandle dataContainer, string name) { + Logger.IfSome(l => l.LogTrace("creating structure by data container handle and name", new { dataContainer, name })); var rc = NativeApi.GetStructure(dataContainer as Native.IDataContainerHandle, name, out var result, out var errorInfo); return ResultOrError((IStructureHandle)result, rc, errorInfo); @@ -130,6 +169,7 @@ public Either GetStructure(IDataContainerHandle public Either GetTable(IDataContainerHandle dataContainer, string name) { + Logger.IfSome(l => l.LogTrace("creating table by data container handle and name", new { dataContainer, name })); var rc = NativeApi.GetTable(dataContainer as Native.IDataContainerHandle, name, out var result, out var errorInfo); return ResultOrError((ITableHandle)result, rc, errorInfo); @@ -137,6 +177,7 @@ public Either GetTable(IDataContainerHandle dataCont public Either CloneTable(ITableHandle tableHandle) { + Logger.IfSome(l => l.LogTrace("cloning table by tableHandle", tableHandle)); ITableHandle handle = NativeApi.CloneTable(tableHandle as TableHandle, out var errorInfo); return ResultOrError(handle, errorInfo); @@ -145,6 +186,7 @@ public Either CloneTable(ITableHandle tableHandle) public Either AllowStartOfPrograms(IConnectionHandle connectionHandle, StartProgramDelegate callback) { + Logger.IfSome(l => l.LogTrace("Setting allow start of programs callback")); NativeApi.AllowStartOfPrograms(connectionHandle as ConnectionHandle, callback, out var errorInfo); return ResultOrError(Unit.Default, errorInfo.Code, errorInfo); @@ -152,6 +194,7 @@ public Either AllowStartOfPrograms(IConnectionHandle connect public Either GetTableRowCount(ITableHandle tableHandle) { + Logger.IfSome(l => l.LogTrace("reading table row count by table handle", tableHandle)); var rc = NativeApi.GetTableRowCount(tableHandle as TableHandle, out var result, out var errorInfo); return ResultOrError(result, rc, errorInfo); @@ -159,6 +202,7 @@ public Either GetTableRowCount(ITableHandle tableHandle) public Either GetCurrentTableRow(ITableHandle tableHandle) { + Logger.IfSome(l => l.LogTrace("reading current table row by table handle", tableHandle)); IStructureHandle handle = NativeApi.GetCurrentTableRow(tableHandle as TableHandle, out var errorInfo); return ResultOrError(handle, errorInfo); @@ -166,6 +210,7 @@ public Either GetCurrentTableRow(ITableHandle ta public Either AppendTableRow(ITableHandle tableHandle) { + Logger.IfSome(l => l.LogTrace("append table row by table handle", tableHandle)); IStructureHandle handle = NativeApi.AppendTableRow(tableHandle as TableHandle, out var errorInfo); return ResultOrError(handle, errorInfo); @@ -173,6 +218,7 @@ public Either AppendTableRow(ITableHandle tableH public Either MoveToNextTableRow(ITableHandle tableHandle) { + Logger.IfSome(l => l.LogTrace("move to next table row by table handle", tableHandle)); var rc = NativeApi.MoveToNextTableRow(tableHandle as TableHandle, out var errorInfo); return ResultOrError(Unit.Default, rc, errorInfo); @@ -180,6 +226,7 @@ public Either MoveToNextTableRow(ITableHandle tableHandle) public Either MoveToFirstTableRow(ITableHandle tableHandle) { + Logger.IfSome(l => l.LogTrace("move to first table row by table handle", tableHandle)); var rc = NativeApi.MoveToFirstTableRow(tableHandle as TableHandle, out var errorInfo); return ResultOrError(Unit.Default, rc, errorInfo); @@ -188,6 +235,7 @@ public Either MoveToFirstTableRow(ITableHandle tableHandle) public Either SetString(IDataContainerHandle containerHandle, string name, string value) { + Logger.IfSome(l => l.LogTrace("setting string value by name", new { containerHandle, name, value})); var rc = NativeApi.SetString(containerHandle as Native.IDataContainerHandle, name, value, out var errorInfo); return ResultOrError(Unit.Default, rc, errorInfo); @@ -195,6 +243,7 @@ public Either SetString(IDataContainerHandle containerHandle public Either GetString(IDataContainerHandle containerHandle, string name) { + Logger.IfSome(l => l.LogTrace("reading string value by name", new { containerHandle, name})); var rc = NativeApi.GetString(containerHandle as Native.IDataContainerHandle, name, out var result, out var errorInfo); return ResultOrError(result, rc, errorInfo); @@ -203,6 +252,7 @@ public Either GetString(IDataContainerHandle containerHand public Either SetDateString(IDataContainerHandle containerHandle, string name, string value) { + Logger.IfSome(l => l.LogTrace("setting date string value by name", new { containerHandle, name, value })); var rc = NativeApi.SetDateString(containerHandle as Native.IDataContainerHandle, name, value, out var errorInfo); return ResultOrError(Unit.Default, rc, errorInfo); @@ -210,6 +260,7 @@ public Either SetDateString(IDataContainerHandle containerHa public Either GetDateString(IDataContainerHandle containerHandle, string name) { + Logger.IfSome(l => l.LogTrace("reading date string value by name", new { containerHandle, name })); var rc = NativeApi.GetDateString(containerHandle as Native.IDataContainerHandle, name, out var result, out var errorInfo); return ResultOrError(result, rc, errorInfo); @@ -218,6 +269,7 @@ public Either GetDateString(IDataContainerHandle container public Either SetTimeString(IDataContainerHandle containerHandle, string name, string value) { + Logger.IfSome(l => l.LogTrace("setting time string value by name", new { containerHandle, name, value })); var rc = NativeApi.SetTimeString(containerHandle as Native.IDataContainerHandle, name, value, out var errorInfo); return ResultOrError(Unit.Default, rc, errorInfo); @@ -225,37 +277,45 @@ public Either SetTimeString(IDataContainerHandle containerHa public Either GetTimeString(IDataContainerHandle containerHandle, string name) { + Logger.IfSome(l => l.LogTrace("getting time string value by name", new { containerHandle, name })); var rc = NativeApi.GetTimeString(containerHandle as Native.IDataContainerHandle, name, out var result, out var errorInfo); return ResultOrError(result, rc, errorInfo); } + public Option Logger { get; } + public Either SetInt(IDataContainerHandle containerHandle, string name, int value) { + Logger.IfSome(l => l.LogTrace("setting int value by name", new { containerHandle, name, value })); var rc = NativeApi.SetInt(containerHandle as Native.IDataContainerHandle, name, value, out var errorInfo); return ResultOrError(Unit.Default, rc, errorInfo); } public Either GetInt(IDataContainerHandle containerHandle, string name) { + Logger.IfSome(l => l.LogTrace("getting int value by name", new { containerHandle, name })); var rc = NativeApi.GetInt(containerHandle as Native.IDataContainerHandle, name, out var result, out var errorInfo); return ResultOrError(result, rc, errorInfo); } public Either SetLong(IDataContainerHandle containerHandle, string name, long value) { + Logger.IfSome(l => l.LogTrace("setting long value by name", new { containerHandle, name, value })); var rc = NativeApi.SetLong(containerHandle as Native.IDataContainerHandle, name, value, out var errorInfo); return ResultOrError(Unit.Default, rc, errorInfo); } public Either GetLong(IDataContainerHandle containerHandle, string name) { + Logger.IfSome(l => l.LogTrace("getting long value by name", new { containerHandle, name })); var rc = NativeApi.GetLong(containerHandle as Native.IDataContainerHandle, name, out var result, out var errorInfo); return ResultOrError(result, rc, errorInfo); } public Either SetBytes(IDataContainerHandle containerHandle, string name, byte[] buffer, long bufferLength) { + Logger.IfSome(l => l.LogTrace("setting byte value by name", new { containerHandle, name })); var rc = NativeApi.SetBytes(containerHandle as Native.IDataContainerHandle, name, buffer, (uint) bufferLength, out var errorInfo); return ResultOrError(Unit.Default, rc, errorInfo); @@ -263,7 +323,7 @@ public Either SetBytes(IDataContainerHandle containerHandle, public Either GetBytes(IDataContainerHandle containerHandle, string name) { - + Logger.IfSome(l => l.LogTrace("getting byte value by name", new { containerHandle, name })); var rc = NativeApi.GetBytes(containerHandle as Native.IDataContainerHandle, name, out var result, out var errorInfo); return ResultOrError(result, rc, errorInfo); } diff --git a/test/SAPSystemTests/Program.cs b/test/SAPSystemTests/Program.cs index a2977204..9143cb68 100644 --- a/test/SAPSystemTests/Program.cs +++ b/test/SAPSystemTests/Program.cs @@ -29,7 +29,7 @@ static async Task Main(string[] args) }; - var runtime = new RfcRuntime(); + var runtime = new RfcRuntime(new SimpleConsoleLogger()); Task> ConnFunc() => Connection.Create(settings, runtime); diff --git a/test/SAPSystemTests/SimpleConsoleLogger.cs b/test/SAPSystemTests/SimpleConsoleLogger.cs new file mode 100644 index 00000000..9e552899 --- /dev/null +++ b/test/SAPSystemTests/SimpleConsoleLogger.cs @@ -0,0 +1,97 @@ +using System; +using System.Collections.Generic; +using System.Text; +using Contiva.SAP.NWRfc; +using Newtonsoft.Json; + +namespace SAPSystemTests +{ + public class SimpleConsoleLogger : ILogger + { + public void LogException(Exception exception, string message) + { + Console.WriteLine($"{message} - Exception: {exception}"); + } + + public void LogException(Exception exception) + { + LogException(exception, ""); + } + + public void LogTrace(string message, object data) + { + Console.WriteLine($"TRACE\t{message}{ObjectToString(data)}"); + } + + public void LogError(string message, object data) + { + Console.WriteLine($"ERROR\t{message}{ObjectToString(data)}"); + } + + public void LogDebug(string message, object data) + { + Console.WriteLine($"DEBUG\t{message}{ObjectToString(data)}"); + } + + public void LogTrace(string message) + { + LogTrace(message, null); + } + + public void LogDebug(string message) + { + LogDebug(message, null); + } + + public void LogError(string message) + { + LogError(message, null); + } + + public static string ObjectToString(object valueObject) + { + var dataString = new StringBuilder(); + if (valueObject == null) + return ""; + + dataString.Append(", Data: "); + + dataString.Append(JsonConvert.SerializeObject(valueObject, new JsonSerializerSettings + { + Converters = new List(new[]{new HandleToStringJsonConverter() }) + })); + + return dataString.ToString(); + + } + + class HandleToStringJsonConverter : JsonConverter + { + public override bool CanConvert(Type objectType) + { + if(objectType.BaseType != null + && objectType.BaseType.FullName != null + && (objectType.BaseType.FullName.StartsWith("Contiva.SAP.NWRfc.Native.HandleBase") + || objectType.BaseType.FullName.StartsWith("Contiva.SAP.NWRfc.Native.DataContainerBase"))) + return true; + return false; + } + + public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) + { + var typeName = value.GetType().Name; + writer.WriteValue($"{typeName}<{value}>"); + } + + public override bool CanRead + { + get { return false; } + } + + public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) + { + throw new NotImplementedException(); + } + } + } +} \ No newline at end of file