Open Closed

AbpAuditLogs and AbpAuditLogActions #218


User avatar
0
lalitChougule created

Check the docs before asking a question: https://docs.abp.io/en/commercial/latest/ Check the samples, to see the basic tasks: https://docs.abp.io/en/commercial/latest/samples/index The exact solution to your question may have been answered before, please use the search on the homepage.

  • ABP Framework version: v2.7.0
  • UI type: Angular
  • Tiered (MVC) or Identity Server Seperated (Angular): no / Yes
  • Exception message and stack trace: N.A
  • Steps to reproduce the issue: N.A

Hi,

I need to know how the record get inserted into AbpAuditLogs and AbpAuditLogActions as I want to implement a bit customized logging of my own. How can I implement the same for my own tables or you can say I just want to insert only few Http Status code related data to my own custom table.

How can I do it ?

Markdown supported.
Copy, paste, or drag & drop images and files (max 100 MB per file, 100 MB total per post)

7 Answer(s)
  • User Avatar
    0
    liangshiwei created
    Fullstack Developer

    Hi,

    See https://docs.abp.io/en/abp/latest/Audit-Logging#audit-log-contributors

    Markdown supported.
    Copy, paste, or drag & drop images and files (max 100 MB per file, 100 MB total per post)
  • User Avatar
    0
    lalitChougule created

    Hi,

    I have implemented Serilog.Sinks.AwsCloudWatch to log my data to AWS-CloudWatch But the problem is according to the documentations of SeriLog I can log data as per LogEventLevel to the CloudWatch which creates huge amout of unnecessary data

    What if I want to log only the data which get logged into AuditLog and AuditLogAction table from database to AWS-CloudWatch.

    Is this possible and how to implement it ?

    Markdown supported.
    Copy, paste, or drag & drop images and files (max 100 MB per file, 100 MB total per post)
  • User Avatar
    0
    liangshiwei created
    Fullstack Developer

    Yes you can.

    You can custom AuditingStore to save auditlog to AWS-CloudWatch.

    Markdown supported.
    Copy, paste, or drag & drop images and files (max 100 MB per file, 100 MB total per post)
  • User Avatar
    0
    lalitChougule created

    Thanks @liangshiwei

    It will be very helpfull if u can provide some sample code to demonstrate implementation of custom AudtingStore

    Markdown supported.
    Copy, paste, or drag & drop images and files (max 100 MB per file, 100 MB total per post)
  • User Avatar
    0
    lalitChougule created

    Hi,

    As you said I tried implementing AudtingStore. But I was not able to log the data like AbpAuditLog.I think I missed out something I got reference from the source code Below is my code , Please help if something is wrong in the implementation

    [Dependency(TryRegister = true)]
    public class AWSAuditingStore: IAuditingStore, ISingletonDependency
        {
            public ILogger<AWSAuditingStore> Logger { get; set; }
    
            public AWSAuditingStore()
            {
                Logger = NullLogger<AWSAuditingStore>.Instance;
            }
    
            public Task SaveAsync(AuditLogInfo auditInfo)
            {
                Logger.LogInformation("AWSAuditingStore : {0}", auditInfo.ToString());
                return Task.FromResult(0);
            }
        }
    
    Markdown supported.
    Copy, paste, or drag & drop images and files (max 100 MB per file, 100 MB total per post)
  • User Avatar
    0
    liangshiwei created
    Fullstack Developer

    Hi,

    I create a simple implementation, but I don't know about AWS-CloudWatch, I hope I can help you.

    [Dependency(ReplaceServices = true)]
    [ExposeServices(typeof(IAuditingStore))]
    public class CustomAuditingStore : AuditingStore
    {
        private readonly LogEventBatch _repo = new LogEventBatch();
        private readonly IAmazonCloudWatchLogs _client;
        private int _requestCount = 5;
    
        private static readonly Regex InvalidSequenceTokenRegex = new
            Regex(@"The given sequenceToken is invalid. The next expected sequenceToken is: (\d+)");
    
        public CustomAuditingStore(
            IAuditLogRepository auditLogRepository,
            IGuidGenerator guidGenerator,
            IUnitOfWorkManager unitOfWorkManager,
            IOptions<AbpAuditingOptions> options)
            : base(auditLogRepository, guidGenerator, unitOfWorkManager, options)
        {
            _client = new AmazonCloudWatchLogsClient(..your config);
        }
    
        public override async Task SaveAsync(AuditLogInfo auditInfo)
        {
            AddSingleMessage(JsonConvert.SerializeObject(auditInfo));
            await SendMessages();
            await base.SaveAsync(auditInfo);
        }
    
        private void AddSingleMessage(string message)
        {
            _repo.AddMessage(new InputLogEvent()
            {
                Timestamp = DateTime.Now,
                Message = message,
            });
        }
    
        private async Task SendMessages()
        {
            try
            {
                //Make sure the log events are in the right order.
                _repo._request.LogEvents.Sort((ev1, ev2) => ev1.Timestamp.CompareTo(ev2.Timestamp));
                var response = await _client.PutLogEventsAsync(_repo._request).ConfigureAwait(false);
                _repo.Reset(response.NextSequenceToken);
                _requestCount = 5;
            }
            catch (InvalidSequenceTokenException ex)
            {
                //In case the NextSequenceToken is invalid for the last sent message, a new stream would be
                //created for the said application.
                if (_requestCount > 0)
                {
                    _requestCount--;
                    var regexResult = InvalidSequenceTokenRegex.Match(ex.Message);
                    if (regexResult.Success)
                    {
                        _repo._request.SequenceToken = regexResult.Groups[1].Value;
                        await SendMessages().ConfigureAwait(false);
                    }
                }
            }
        }
    }
    
    /// <summary>
    /// Class to handle PutLogEvent request and associated parameters.
    /// Also has the requisite checks to determine when the object is ready for Transmission.
    /// </summary>
    public class LogEventBatch
    {
        public TimeSpan TimeIntervalBetweenPushes { get; private set; }
        public int MaxBatchSize { get; private set; }
    
        public bool ShouldSendRequest(int maxQueuedEvents)
        {
            if (_request.LogEvents.Count == 0)
            {
                return false;
            }
    
            if (_nextPushTime < DateTime.UtcNow)
            {
                return true;
            }
    
            if (maxQueuedEvents <= _request.LogEvents.Count)
            {
                return true;
            }
    
            return false;
        }
    
        int _totalMessageSize { get; set; }
        DateTime _nextPushTime;
        public PutLogEventsRequest _request = new PutLogEventsRequest();
    
        public LogEventBatch(string logGroupName, string streamName, int timeIntervalBetweenPushes, int maxBatchSize)
        {
            _request.LogGroupName = logGroupName;
            _request.LogStreamName = streamName;
            TimeIntervalBetweenPushes = TimeSpan.FromSeconds(timeIntervalBetweenPushes);
            MaxBatchSize = maxBatchSize;
            Reset(null);
        }
    
        public LogEventBatch()
        {
        }
    
        public int CurrentBatchMessageCount
        {
            get { return this._request.LogEvents.Count; }
        }
    
        public bool IsEmpty => _request.LogEvents.Count == 0;
    
        public bool IsSizeConstraintViolated(string message)
        {
            Encoding unicode = Encoding.Unicode;
            int prospectiveLength = _totalMessageSize + unicode.GetMaxByteCount(message.Length);
            if (MaxBatchSize < prospectiveLength)
                return true;
    
            return false;
        }
    
        public void AddMessage(InputLogEvent ev)
        {
            Encoding unicode = Encoding.Unicode;
            _totalMessageSize += unicode.GetMaxByteCount(ev.Message.Length);
            _request.LogEvents.Add(ev);
        }
    
        public void Reset(string SeqToken)
        {
            _request.LogEvents.Clear();
            _totalMessageSize = 0;
            _request.SequenceToken = SeqToken;
            _nextPushTime = DateTime.UtcNow.Add(TimeIntervalBetweenPushes);
        }
    }
    
    Markdown supported.
    Copy, paste, or drag & drop images and files (max 100 MB per file, 100 MB total per post)
  • User Avatar
    0
    lalitChougule created

    Thanks alot @liangshiwei It worked

    Markdown supported.
    Copy, paste, or drag & drop images and files (max 100 MB per file, 100 MB total per post)
Boost Your Development
ABP Live Training
Packages
See Trainings
Mastering ABP Framework Book
The Official Guide
Mastering
ABP Framework
Learn More
Mastering ABP Framework Book
Made with ❤️ on ABP v10.8.0-preview. Updated on September 16, 2026, 14:50
1
ABP Assistant
🔐 You need to be logged in to use the chatbot. Please log in first.