aboutsummaryrefslogtreecommitdiffstats
path: root/Software/Visual_Studio/MachineStudio/Tango.MachineStudio.Common/EventLogging/DefaultEventLogger.cs
blob: 89b8920d981f8cff09107a9f03c00b9e1d40a797 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
3
using Google.Protobuf;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Tango.BL;
using Tango.BL.Entities;
using Tango.BL.Enumerations;
using Tango.Core;
using Tango.Integration.ExternalBridge;
using Tango.Logging;
using Tango.MachineStudio.Common.Authentication;
using Tango.MachineStudio.Common.Diagnostics;
using Tango.MachineStudio.Common.StudioApplication;
using Tango.PMR.Diagnostics;
using Tango.Integration.Operation;
using Tango.Core.ExtensionMethods;
using Tango.Transport;

namespace Tango.MachineStudio.Common.EventLogging
{
    /// <summary>
    /// Represents the default database events logger.
    /// </summary>
    /// <seealso cref="IEventLogger" />
    public class DefaultEventLogger : ExtendedObject, IEventLogger
    {
        private ObservablesContext _db;
        private static object _lockInit = new object();
        private Thread _logThread;
        private ConcurrentQueue<MachinesEvent> _events;
        private IStudioApplicationManager _application;
        private IAuthenticationProvider _authentication;
        private Dictionary<EventTypes, BL.Entities.EventType> _eventTypesGuids;
        private String _hostName;
        private bool _isInitialized;
        private List<MachinesEvent> _pendingEvents;

        #region Events

        /// <summary>
        /// Occurs when a new machine event has been logged.
        /// </summary>
        public event EventHandler<MachinesEvent> NewLog;

        #endregion

        #region Properties

        /// <summary>
        /// Gets or sets a value indicating whether to save the incoming events to database.
        /// </summary>
        public bool SaveToDB { get; set; }

        #endregion

        #region Constructors

        /// <summary>
        /// Initializes a new instance of the <see cref="DefaultEventLogger"/> class.
        /// </summary>
        /// <param name="applicationManager">The application manager.</param>
        /// <param name="authenticationProvider">The authentication provider.</param>
        public DefaultEventLogger(IStudioApplicationManager applicationManager, IAuthenticationProvider authenticationProvider)
        {
            _hostName = Environment.MachineName;

            SaveToDB = true;

            _events = new ConcurrentQueue<MachinesEvent>();
            _pendingEvents = new List<MachinesEvent>();

            _eventTypesGuids = new Dictionary<EventTypes, BL.Entities.EventType>();

            _application = applicationManager;
            _authentication = authenticationProvider;
            _logThread = new Thread(LogThreadMethod);
            _logThread.IsBackground = true;
            _logThread.Start();

            _application.ConnectedMachineChanged += _application_ConnectedMachineChanged;
        }

        #endregion

        #region Private Methods

        private void Init()
        {
            lock (_lockInit)
            {
                if (!_isInitialized)
                {
                    try
                    {
                        _db = ObservablesContext.CreateDefault();

                        _db.EventTypes.ToList();

                        foreach (var type in _db.EventTypes)
                        {
                            _eventTypesGuids.Add((EventTypes)type.Code, type);
                        }

                        _isInitialized = true;
                    }
                    catch
                    {
                        _isInitialized = false;
                    }
                }
            }
        }

        #endregion

        #region Event Handlers

        /// <summary>
        /// Handle the application manager connected machine changed event.
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="machine">The machine.</param>
        private void _application_ConnectedMachineChanged(object sender, IExternalBridgeClient machine)
        {
            if (machine != null)
            {
                if (machine.MachineEventsStateProvider != null)
                {
                    machine.MachineEventsStateProvider.NewEvents -= MachineEventsStateProvider_NewEvents;
                    machine.MachineEventsStateProvider.NewEvents += MachineEventsStateProvider_NewEvents;
                    machine.MachineEventsStateProvider.EventsResolved -= MachineEventsStateProvider_EventsResolved;
                    machine.MachineEventsStateProvider.EventsResolved += MachineEventsStateProvider_EventsResolved;
                }

                machine.RequestSent -= Machine_RequestSent;
                machine.RequestFailed -= Machine_RequestFailed;
                machine.ResponseReceived -= Machine_ResponseReceived;

                machine.RequestSent += Machine_RequestSent;
                machine.RequestFailed += Machine_RequestFailed;
                machine.ResponseReceived += Machine_ResponseReceived;

                SaveToDB = !(machine is IExternalBridgeSecureClient);
            }
        }

        /// <summary>
        /// Handles the RequestSent event of the connected machine.
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="message">The message.</param>
        private void Machine_RequestSent(object sender, IMessage message)
        {
            //Log(EventTypes.REQUEST_SENT, String.Format("Sending request '{0}'...{1}{2}", message.GetType().Name, Environment.NewLine, message.ToJsonString()));
        }

        /// <summary>
        /// Handles the RequestFailed event of the connected machine.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="RequestFailedEventArgs"/> instance containing the event data.</param>
        private void Machine_RequestFailed(object sender, RequestFailedEventArgs e)
        {
            //Log(EventTypes.REQUEST_FAILED, String.Format("Request failed '{0}'...{1}{2}{1}{3}", e.Message.GetType().Name, Environment.NewLine, e.Message.ToJsonString(), e.Exception.ToString()));
        }

        /// <summary>
        /// Handles the ResponseReceived event of the connected machine.
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="message">The message.</param>
        private void Machine_ResponseReceived(object sender, IMessage message)
        {
            //Log(EventTypes.RESPONSE_RECEIVED, String.Format("Response received '{0}'...{1}{2}", message.GetType().Name, Environment.NewLine, message.ToJsonString()));
        }

        /// <summary>
        /// Handles the connected machine events state provider NewEvents event.
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="events">The events.</param>
        private void MachineEventsStateProvider_NewEvents(object sender, IEnumerable<MachinesEvent> events)
        {
            foreach (var ev in events)
            {
                Log(ev);
            }
        }

        /// <summary>
        /// Handles the connected machine events state provider EventsResolved event.
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="events">The events.</param>
        private void MachineEventsStateProvider_EventsResolved(object sender, IEnumerable<MachinesEvent> events)
        {
            //foreach (var ev in events)
            //{
            //    Log(String.Format("Event '{0}' resolved.", ev.EventType.Name));
            //}
        }

        #endregion

        #region Logging

        /// <summary>
        /// Logs the specified machine event.
        /// </summary>
        /// <param name="machineEvent">The machine event.</param>
        public void Log(MachinesEvent machineEvent)
        {
            Init();

            machineEvent.HostName = _hostName;
            machineEvent.EventType = _eventTypesGuids[machineEvent.Type];

            if (_application.ConnectedMachine == null || _authentication.CurrentUser == null)
            {
                _pendingEvents.Add(machineEvent);
            }
            else
            {
                lock (_pendingEvents)
                {
                    if (_pendingEvents.Count > 0)
                    {
                        var pending = _pendingEvents.ToList();
                        _pendingEvents.Clear();

                        foreach (var ev in pending)
                        {
                            Log(ev);
                        }
                    }
                }

                LogManager.Log("Logging event " + machineEvent.EventType.Name);
                machineEvent.MachineGuid = _application.Machine.Guid;
                machineEvent.UserGuid = _authentication.CurrentUser.Guid;
                machineEvent.User = _authentication.CurrentUser;
                _events.Enqueue(machineEvent);
                NewLog?.Invoke(this, machineEvent);
            }
        }

        /// <summary>
        /// Logs the specified event type.
        /// </summary>
        /// <param name="eventType">Type of the event.</param>
        /// <param name="message">The message.</param>
        public void Log(EventTypes eventType, string message, bool write_to_db = true)
        {
            Init();

            MachinesEvent machineEvent = new MachinesEvent();
            machineEvent.DateTime = DateTime.UtcNow;
            machineEvent.Description = message;
            machineEvent.EventType = _eventTypesGuids[eventType];
            machineEvent.EventTypeGuid = machineEvent.EventType.Guid;

            if (write_to_db && SaveToDB)
            {
                Log(machineEvent);
            }
            else
            {
                NewLog?.Invoke(this, machineEvent);
            }
        }

        /// <summary>
        /// Logs the specified hardware event.
        /// </summary>
        /// <param name="hardwareEvent">The hardware event.</param>
        public void Log(Event hardwareEvent)
        {
            Log((EventTypes)hardwareEvent.Type, hardwareEvent.Message);
        }

        /// <summary>
        /// Logs the specified exception using the <see cref="EventTypes.ApplicationException"/>.
        /// </summary>
        /// <param name="exception">The exception.</param>
        public void Log(Exception exception)
        {
            Log(EventTypes.APPLICATION_EXCEPTION, exception.ToString());
        }

        /// <summary>
        /// Logs the specified exception using the <see cref="EventTypes.ApplicationException" />.
        /// </summary>
        /// <param name="exception">The exception.</param>
        /// <param name="description"></param>
        public void Log(Exception exception, string description)
        {
            Log(EventTypes.APPLICATION_EXCEPTION, description + Environment.NewLine + exception.ToString());
        }

        /// <summary>
        /// Logs the specified message using the <see cref="EventTypes.ApplicationInformation"/>.
        /// </summary>
        /// <param name="message">The message.</param>
        public void Log(String message)
        {
            Log(EventTypes.APPLICATION_INFORMATION, message);
        }

        /// <summary>
        /// Logging thread loop.
        /// </summary>
        private void LogThreadMethod()
        {
            while (true)
            {
                FlushAll();
                Thread.Sleep(5000);
            }
        }

        /// <summary>
        /// Immediately saves all pending events to database.
        /// </summary>
        public void FlushAll()
        {
            if (!SaveToDB)
            {
                return;
            }

            bool _saveChanges = false;

            while (_events.Count > 0)
            {
                MachinesEvent ev = null;

                if (_events.TryDequeue(out ev))
                {
                    ev.User = null;
                    _db.MachinesEvents.Add(ev);
                    _saveChanges = true;
                }
            }

            if (_saveChanges)
            {
                try
                {
                    _db.SaveChanges();
                }
                catch (Exception ex)
                {
                    LogManager.Log(ex, "Error saving machine event to database.");
                }
            }
        }

        #endregion
    }
}