Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<Version>10.4.23</Version>
<Version>10.4.24</Version>
<AssemblyVersion>1.0.0.0</AssemblyVersion>
<Title>Live Integration</Title>
<Description>Live Integration</Description>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ public LiveContext(Currency currency, User user, Shop shop)
Currency = currency;
User = user;
Shop = shop;
Country = GetCountry(user);
Country = Common.Context.Country ?? GetCountry(user);
}

public LiveContext(PriceContext priceContext)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
[AddInIgnore(false)]
[AddInUseParameterGrouping(true)]
[AddInUseParameterOrdering(true)]
public class LiveIntegrationAddIn : BaseLiveIntegrationAddIn, IDropDownOptions, ISettings

Check warning on line 32 in src/Dynamicweb.Ecommerce.DynamicwebLiveIntegration/LiveIntegrationAddIn.cs

View workflow job for this annotation

GitHub Actions / call-workflow / Build

'IDropDownOptions' is obsolete: 'Use IParameterOptions instead.'

Check warning on line 32 in src/Dynamicweb.Ecommerce.DynamicwebLiveIntegration/LiveIntegrationAddIn.cs

View workflow job for this annotation

GitHub Actions / call-workflow / Build

'IDropDownOptions' is obsolete: 'Use IParameterOptions instead.'
{
/// <summary>
/// Initializes a new instance of the <see cref="LiveIntegrationAddIn"/> class.
Expand Down Expand Up @@ -816,6 +816,7 @@
Licensing.LicenseService.SaveSettings(settings);
SaveTranslations(settings);
Connector.ClearCache();
Logger.ClearLogMessages(settings);
}

/// <summary>
Expand Down
223 changes: 129 additions & 94 deletions src/Dynamicweb.Ecommerce.DynamicwebLiveIntegration/Logging/Logger.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
using Dynamicweb.Mailing;
using Dynamicweb.Rendering;
using System;
using System.Collections.Concurrent;
using System.IO;
using System.Linq;
using System.Threading;
Expand All @@ -18,31 +19,27 @@ public class Logger
{
private static readonly string DateTimeFormat = "yyyy-MM-dd HH:mm:ss.ffff";

/// <summary>
/// The synchronize lock.
/// </summary>
private static readonly object SyncLock = new();

/// <summary>
/// The log file
/// </summary>
private readonly string _logFile;

private readonly Settings _settings;
private readonly TimeSpan _waitTimeout;
private readonly NotificationFrequency _notificationFrequency;
private static readonly ConcurrentDictionary<string, ConcurrentQueue<string>> _lastLogMessages = new();
private readonly int _lastLogMessagesLimit = 100;

/// <summary>
/// Prevents a default instance of the <see cref="Logger"/> class from being created.
/// </summary>
public Logger(Settings settings)
{
_settings = settings;
if (settings != null)
{
if (string.IsNullOrEmpty(_logFile))
{
_logFile = SystemInformation.MapPath($"/Files/System/Log/LiveIntegration/{settings.InstanceName}.log");
}
}

_logFile = SystemInformation.MapPath($"/Files/System/Log/LiveIntegration/{settings.InstanceName}.log");
_waitTimeout = TimeSpan.FromSeconds(settings.AutoPingInterval < Constants.MinPingInterval ? Constants.MinPingInterval : settings.AutoPingInterval);
_notificationFrequency = Helpers.GetEnumValueFromString(_settings.NotificationSendingFrequency, NotificationFrequency.Never);
}

/// <summary>
Expand All @@ -69,74 +66,22 @@ public Logger(Settings settings)
/// <value><c>true</c> if [log response errors]; otherwise, <c>false</c>.</value>
private bool LogResponseErrors => _settings.LogResponseErrors;

/// <summary>
/// Sends an mail with error information according to configuration.
/// </summary>
/// <param name="message">The error/success message to send.</param>
/// <returns><c>true</c> if email was sent, <c>false</c> otherwise.</returns>
public bool SendMail(string message)
{
string notificationTemplate = _settings.NotificationTemplate;
if (string.IsNullOrEmpty(message) || string.IsNullOrEmpty(notificationTemplate))
return false;

var recipients = _settings.NotificationRecipients;
if (recipients is null || !recipients.Any())
return false;

Template templateInstance = new($"/DataIntegration/Notifications/{notificationTemplate}");
templateInstance.SetTag("Ecom:LiveIntegration.AddInName", Constants.AddInName);
templateInstance.SetTag("Ecom:LiveIntegration.ErrorMessage", message);

string notificationEmailSubject = _settings.NotificationEmailSubject;
string notificationEmailSenderEmail = _settings.NotificationEmailSenderEmail;
string notificationEmailSenderName = _settings.NotificationEmailSenderName;

using var mail = new System.Net.Mail.MailMessage();
mail.IsBodyHtml = true;
mail.Subject = notificationEmailSubject;
mail.SubjectEncoding = System.Text.Encoding.UTF8;
mail.From = new(notificationEmailSenderEmail, notificationEmailSenderName, System.Text.Encoding.UTF8);

// Set parameters for MailMessage
foreach (var email in recipients)
mail.To.Add(email);
mail.BodyEncoding = System.Text.Encoding.UTF8;

// Render Template and set as Body
mail.Body = templateInstance.Output();

// Send mail
return EmailHandler.Send(mail);
}

/// <summary>
/// Gets the error messages sine the last email was sent.
/// </summary>
/// <returns>Log data</returns>
/// <returns>Log data</returns>
public string GetLastLogData()
{
string result = string.Empty;

lock (SyncLock)
if (_lastLogMessages.TryGetValue(_logFile, out var queue))
{
foreach (var line in File.ReadLines(_logFile, System.Text.Encoding.UTF8).Reverse())
var lines = queue.ToList();
foreach (var line in lines)
{
if (line.Contains(ErrorLevel.DebugInfo.ToString()))
{
// ignore debug info
}
else if (!line.Contains(ErrorLevel.EmailSend.ToString()))
{
result += line + "<br>";
}
else
{
break;
}
result += line + "<br>";
}
}

return result;
}

Expand All @@ -147,18 +92,22 @@ public string GetLastLogData()
/// <param name="logline">The log line.</param>
public void Log(ErrorLevel errorLevel, string logline)
{
if (!string.IsNullOrEmpty(_logFile))
bool isAllowedAddToLog = IsAllowedAddToLog(errorLevel);
if (isAllowedAddToLog)
{
bool isAllowedAddToLog = IsAllowedAddToLog(errorLevel);
lock (SyncLock)
logline = $"{DateTime.Now.ToString(DateTimeFormat)}: {errorLevel}: {logline}{System.Environment.NewLine}";

TryAddLogLineToQueue(errorLevel, logline);

using (var mutex = new Mutex(false, _logFile.Replace("\\", "")))
{
if (isAllowedAddToLog)
var hasHandle = false;
try
{
KeepOrTruncateFile();
logline = $"{DateTime.Now.ToString(DateTimeFormat)}: {errorLevel}: {logline}{System.Environment.NewLine}";

hasHandle = mutex.WaitOne(_waitTimeout, false);
KeepOrTruncateFile();
try
{
{
TextFileHelper.WriteTextFile(logline, _logFile, true, System.Text.Encoding.UTF8);
}
catch (IOException)
Expand All @@ -173,12 +122,39 @@ public void Log(ErrorLevel errorLevel, string logline)
TextFileHelper.WriteTextFile(logline, fileName, false, System.Text.Encoding.UTF8);
}
}
catch (Exception)
{
throw;
}
finally
{
if (hasHandle)
mutex.ReleaseMutex();
}
}
}

if (errorLevel != ErrorLevel.DebugInfo && errorLevel != ErrorLevel.EmailSend)
if (errorLevel != ErrorLevel.DebugInfo && errorLevel != ErrorLevel.EmailSend)
{
SendLog(logline, isAllowedAddToLog);
}
}

private void TryAddLogLineToQueue(ErrorLevel errorLevel, string logline)
{
if (errorLevel != ErrorLevel.DebugInfo && errorLevel != ErrorLevel.EmailSend && _notificationFrequency != NotificationFrequency.Never)
{
_lastLogMessages.AddOrUpdate(_logFile,
new ConcurrentQueue<string>([logline]),
(k, q) =>
{
SendLog(logline, isAllowedAddToLog);
}
q.Enqueue(logline);
if (q.Count > _lastLogMessagesLimit)
{
q.TryDequeue(out _);
}
return q;
});
}
}

Expand Down Expand Up @@ -275,54 +251,107 @@ private void MoveToHistoryFile(FileInfo fi)
/// <param name="isLastErrorInLog">if set to <c>true</c> [is last error in log].</param>
private void SendLog(string lastError, bool isLastErrorInLog)
{
string frequencySettings = _settings.NotificationSendingFrequency;
if (string.IsNullOrEmpty(frequencySettings))
{
return;
}

var frequency = Helpers.GetEnumValueFromString(frequencySettings, NotificationFrequency.Never);
if (frequency == NotificationFrequency.Never)
if (_notificationFrequency == NotificationFrequency.Never)
{
return;
}

// Get last time when the email was sent
DateTime lastTimeSend = Settings.LastNotificationEmailSent;
DateTime lastTimeSend = Settings.LastNotificationEmailSent;
bool emailSent = false;
if (lastTimeSend == DateTime.MinValue)
{
// used for getting the last errors appeared for the future email
Settings.LastNotificationEmailSent = DateTime.Now;
emailSent = SendMail(lastError);
emailSent = SendMail(lastError, false);
}
else
{
// send email if the frequency interval already passed
if (DateTime.Now.Subtract(lastTimeSend) >= TimeSpan.FromMinutes((double)frequency))
if (DateTime.Now.Subtract(lastTimeSend) >= TimeSpan.FromMinutes((double)_notificationFrequency))
{
Settings.LastNotificationEmailSent = DateTime.Now;
if (!isLastErrorInLog)
{
emailSent = SendMail(GetLastLogData() + lastError);
emailSent = SendMail(lastError, true);
}
else
{
emailSent = SendMail(GetLastLogData());
emailSent = SendMail(null, true);
}
}
}

if (emailSent)
{
Log(ErrorLevel.EmailSend, "Send e-mail with errors");
_lastLogMessages.TryRemove(_logFile, out _);
}
else
{
{
Settings.LastNotificationEmailSent = lastTimeSend;
}
}

[Obsolete("Use SendMail(string message, bool getLastLogData) instead")]
public bool SendMail(string message)
{
return SendMail(message, true);
}

/// <summary>
/// Sends an mail with error information according to configuration.
/// </summary>
/// <param name="message">The error/success message to send.</param>
/// <returns><c>true</c> if email was sent, <c>false</c> otherwise.</returns>
public bool SendMail(string message, bool getLastLogData)
{
string notificationTemplate = _settings.NotificationTemplate;
if (string.IsNullOrEmpty(notificationTemplate))
return false;

var recipients = _settings.NotificationRecipients;
if (recipients is null || recipients.Count == 0)
return false;

Template templateInstance = new($"/DataIntegration/Notifications/{notificationTemplate}");
templateInstance.SetTag("Ecom:LiveIntegration.AddInName", Constants.AddInName);
bool logMsgTagExists = templateInstance.TagExists("Ecom:LiveIntegration.ErrorMessage");
if (logMsgTagExists)
{
if (getLastLogData)
{
message = GetLastLogData() + message;
}
templateInstance.SetTag("Ecom:LiveIntegration.ErrorMessage", message);
}

string notificationEmailSubject = _settings.NotificationEmailSubject;
string notificationEmailSenderEmail = _settings.NotificationEmailSenderEmail;
if (!StringHelper.IsValidEmailAddress(notificationEmailSenderEmail))
{
notificationEmailSenderEmail = EmailHandler.SystemMailFromAddress();
}
string notificationEmailSenderName = _settings.NotificationEmailSenderName;

using var mail = new System.Net.Mail.MailMessage();
mail.IsBodyHtml = true;
mail.Subject = notificationEmailSubject;
mail.SubjectEncoding = System.Text.Encoding.UTF8;
mail.From = new(notificationEmailSenderEmail, notificationEmailSenderName, System.Text.Encoding.UTF8);

// Set parameters for MailMessage
foreach (var email in recipients)
mail.To.Add(email);
mail.BodyEncoding = System.Text.Encoding.UTF8;

// Render Template and set as Body
mail.Body = templateInstance.Output();

// Send mail
return EmailHandler.Send(mail);
}

/// <summary>
/// Truncates the log file.
/// </summary>
Expand Down Expand Up @@ -375,5 +404,11 @@ private void TruncateLogFileFileInfo(FileInfo fi, int maxSize)
TextFileHelper.WriteTextFile(logLine, _logFile, true, System.Text.Encoding.UTF8);
}
}

internal static void ClearLogMessages(Settings settings)
{
var logFile = SystemInformation.MapPath($"/Files/System/Log/LiveIntegration/{settings.InstanceName}.log");
_lastLogMessages.TryRemove(logFile, out _);
}
}
}
Loading
Loading