System rejestrowania czynności użytkownika (tworzenie logów)

0

Cześć wszystkim.
Czy jest jakiś sposób aby zbierać i zapisywać wszystkie czynności, które przeprowadza zalogowany użytkownik na aplikacji strony (logi)?

10

Tak, da się tak zrobić.

0

@cerrato: Mógłbyś jeszcze napisać... "Wiem, ale nie powiem"

1

Standardowo w .NET używa się loggerów jak NLog czy Serilog, a to jak wygląda wynikowy format i gdzie lądują logi znajduje się w ich konfiguracji.
Zamiast ładować log do pliku można wybrać bardziej fancy narzedzie, gdzie logi będzie można przeglądać inaczej niż grepem.

4
Neosphoros napisał(a):

Cześć wszystkim.

Czy jest jakiś sposób aby zbierać i zapisywać wszystkie czynności, które przeprowadza zalogowany użytkownik na aplikacji strony (logi)?

Zacznij od tego po co Ci ta informacja. Jeżeli chcesz np. monitorować serwis pod względem tego jakie np. produkty ktoś przegląda, to może coś ala Google Analitics?

Jeżeli chodzi natomiast o weryfikację jakichś firmowych reguł, to chyba trzeba by było przy wywołaniach metod przekazywać ich parametry i kto wywołał i zapisywać do jakiejś bazy? W Javie to można np. programowaniem aspektowym zrealizować.

@Neosphoros zanim zaczniesz coś działać, to napisz konkretnie jaki problem chcesz rozwiązać - czyli co takie informacje mają ci dać.

0

@.andy: Miałoby się to opierać o rejestrację zmian na bazie danych takich jak kto się zalogował, data i czas tej czynności, dodanie rekordu, jego zmiana, usunięcie i kto wykonał te czynności.

1
Neosphoros napisał(a):

@.andy: Miałoby się to opierać o rejestrację zmian na bazie danych takich jak kto się zalogował, data i czas tej czynności, dodanie rekordu, jego zmiana, usunięcie i kto wykonał te czynności.

No dobra ale dalej nie odpowiedziałeś na pytanie. Po co ci te dane i co z nimi chcesz później robić. Ma to być w celach audytowych?

0

@.andy: W celu weryfikacji nieumyślnego lub celowego wprowadzenia błędnych danych do bazy i dzięki tej możliwości - zmiany błędu na wartość właściwą.

0
Neosphoros napisał(a):

@.andy: W celu weryfikacji nieumyślnego lub celowego wprowadzenia błędnych danych do bazy i możliwości zmiany błędu na wartość właściwą.

Spotkałem się w jednym z CRMów z podejściem trzymania historii dla wpisów. Czyli powiedzmy, że masz sobie Kontrahenta. Teraz w zależności od uprawnień każdy może go edytować no i jak piszesz mogą pojawić się pomyłki.
System trzyma dla tego rekordu historię zmian dzięki czemu wchodząc na tę pozycję możesz jednym kliknięciem przywrócić np. poprzednią wartość.

Rozwiązanie problemu zupełnie inne niż te wyżej. Widzisz jak bardzo w czymś takim zmienia pokazanie o jaki problem chodzi?

0

@.andy: Czyli można przyjąć, że można by te zmiany rejestrować w kolejnej bazie danych by łatwiej znajdować potrzebne informacje. Czy jest jakaś gotowa logika o tym mówiąca?

0

@Neosphoros: nie tyle oddzielnej bazie danych co oddzielnej tabeli dla każdego typu rekordu. Np. Kontrachenci mają inne pola niż Osoba, Wydarzenie czy Telefon.

Wydaje mi się (ale tylko mi się wydaje i można mnie poprawić) najlepszym rozwiązaniem by było stworzenie ich per każdy element dla którego zależy Ci na historii zmian. Przed zapisaniem z bazy pobierasz obecne informacje na temat tego elementu i po poprawnej zmianie zapisujesz je do tabelki history.

Warto też na froncie zrobić przycisk który pokazuje historię i pozwala na przywrócenie konkretnej wersji danych.

Napisz konkretnie co to za system, to jeszcze lepiej będzie można doradzić.

0

@.andy: Czyli jak zgaduje taka tabela (lub dodatkowa) musiałaby zapamiętywać ostatni stan takiego elementu by móc porównać go z nowym i jeśli nowy byłby inny to zapisać go w "logu". Czy oznacza to, że każdy element mogący podlegać edycji musiałby być nadzorowany przez jakąś funkcję sprawdzającą? To chyba dużo roboty (if'ów)? Nie ma jakiegoś łatwiejszego rozwiązania? A i jak to powiązać z tym kto w danej chwili jest zalogowany? ...i w końcu - jak umożliwić zalogowanie się w tym samym czasie kilku użytkowników, którzy będą mogli przeprowadzać czynności na tych samych danych? To będzie chyba dużo tabel? Coś mi się wydaje, że przez przypadek stworzę nową SI ;)

0

Czyli jak zgaduje taka tabela (lub dodatkowa) musiałaby zapamiętywać ostatni stan takiego elementu by móc porównać go z nowym i jeśli nowy byłby inny to zapisać go w "logu".

Nie. Ja to widzę tak, że w momencie persystencji np. Kontrahenta pobierasz jego obecną wartość z bazy i próbujesz zapisać to co prześle użytkownik. Jak operacja się powiedzie, to pobraną z bazy wersję sprzed zapisu zapisujesz do tabelki Kontrahent Historia czy jakoś tak.

Czy oznacza to, że każdy element mogący podlegać edycji musiałby być nadzorowany przez jakąś funkcję sprawdzającą? To chyba dużo roboty (if'ów)? Nie ma jakiegoś łatwiejszego rozwiązania?

Jak pisałem wcześniej ta funkcjonalność pasuje mi idealnie do programowania aspektowego.

A i jak to powiązać z tym kto w danej chwili jest zalogowany?

Do serwisu który robi persystencję pewnie musiałaby spływać taka informacja - no. id użytkownika. Czyli ktoś klikając zapisz rekord strzela do backendu przekazując zmieniony rekord i m.in. id osoby, która go zmieniła.

i w końcu - jak umożliwić zalogowanie się w tym samym czasie kilku użytkowników, którzy będą mogli przeprowadzać czynności na tych samych danych?

Nie znam się ale się wypowiem :D Wydaje mi się że przy kliknięciu edycja na rekordzie powinna być robiona jednak blokada tego rekordu na jakiś czas, bo inaczej mogło by dojść do niespodziewanych efektów, czyli handlowiec edytuje firmę w wersji 1.5, zmienia dane i chce kliknąć zapisz a w tym samym czasie kolejny handlowiec też klika zapisz.

Jeśli piszę bzdury to niech mnie ktoś poprawi.

1

Ja kiedyś podobny problem rozwiązałem za pomocą ActionFilter dla IActionResult. (przykład dla ASP.NET Core)

Dla przykładu, użytkownik wypełnia i wysyła formularz:

[HttpPost]
        [AllowAnonymous]
        [ServiceFilter(typeof(SearchAuditActionFilter))] //filtr akcji
        public async Task<IActionResult> SearchResults(SearchModel searchModel)
        {
            //logika wyszukiwania
        }

SearchAuditActionFilter musi być zarejestrowany w Startup.cs:

services.AddScoped<SearchAuditActionFilter>();

Definiujesz sobie atrybut:

public class SearchAuditActionFilter : ActionFilterAttribute
    {
        //zależności, możesz dodać warstwę bazy danych
        private readonly IUserService _user;

        public SearchAuditActionFilter(IUserService user)
        {
            _user = user;
        }

        public override async Task OnActionExecutionAsync(ActionExecutingContext filterContext, ActionExecutionDelegate next)
        {
            //logika porównania danych i zapisu do bazy / pliku / gdziekolwiek
            //dużo danych możesz pozyskać z filterContext jak i wstrzykniętych zależności
        }
    }
1

Przecież zgodnie z tym co piszesz wcale nie potrzebujesz logowania (post-factum), ale bardziej uwierzytelniania i autoryzacji.

Edit: może nie tyle co wcale, ale nie jest to sednem problemu. Dostęp do zasobów powinien być sprawdzany przed ich modyfikacją, a nie po, żeby sprawdzić kto, co i kiedy zespuł.

3

Spotkałem się w jednym z CRMów z podejściem trzymania historii dla wpisów. Czyli powiedzmy, że masz sobie Kontrahenta. Teraz w zależności od uprawnień każdy może go edytować no i jak piszesz mogą pojawić się pomyłki.
System trzyma dla tego rekordu historię zmian dzięki czemu wchodząc na tę pozycję możesz jednym kliknięciem przywrócić np. poprzednią wartość.

Wydaje mi się, że (przynajmniej w przypadku kluczowych danych takich jak kontrahent) większość CRM'ów tak ma.

Wyobraź sobie, że masz klienta, który w jakimś momencie zmienia swoją siedzibę. Cała reszta (NIP, nazwa, mail, telefony itp.) pozostają bez zmian, ale przenosi się z Konina ul. Truskawkowa do Leszna ul. Zielona. Poprawiasz jego dane w systemie i co się dzieje? Okazuje się, że historyczne dokumenty (w których przecież nie masz na sztywno wpisanego adresu, ale jedynie odniesienie do tabeli z kontrahentami) także ulegną poprawieniu i drukując fakturę sprzed 2 lat dostaniesz wydruk z nowymi danymi. A przecież te 2 lata temu prawidłowy był adres sprzed zmiany.

Dlatego robi się tak, że nie zmienia się adresów, ale jedynie tworzy nowy adres w tabeli z adresami i wiąże się go z danym kontrahentem - jako adres bieżący. Nie ma to w żaden sposób wpływu na inne dokumenty, które zostały wystawione. Jednocześnie (nawiązując do głównego pytania w tym wątku) wystarczy zapisać do logów, że dany user wprowadził zmianę danych adresowych kontrahenta, poprzedni adres miał ID=324, po zmianie mamy adres o ID=1833. Mając tylko taką informację właściwie wiemy wszystko - kto zmienił, kiedy, z czego i na co. A jednocześnie w logu za wiele trzymać nie musimy.

1

@cerrato:

Wyobraź sobie, że masz klienta, który w jakimś momencie zmienia swoją siedzibę. Cała reszta (NIP, nazwa, mail, telefony itp.) pozostają bez zmian, ale przenosi się z Konina ul. Truskawkowa do Leszna ul. Zielona. Poprawiasz jego dane w systemie i co się dzieje? Okazuje się, że historyczne dokumenty (w których przecież nie masz na sztywno wpisanego adresu, ale jedynie odniesienie do tabeli z kontrahentami) także ulegną poprawieniu i drukując fakturę sprzed 2 lat dostaniesz wydruk z nowymi danymi. A przecież te 2 lata temu prawidłowy był adres sprzed zmiany.

No tutaj się zgadzam. Ogólnie to przykład był bardzo ogólny i miał raczej pokazać takie globalne spojrzenie.

Dlatego robi się tak, że nie zmienia się adresów, ale jedynie tworzy nowy adres w tabeli z adresami i wiąże się go z danym kontrahentem - jako adres bieżący. Nie ma to w żaden sposób wpływu na inne dokumenty, które zostały wystawione.

No spotykałem się z takimi podejściami w systemach, że takie dane nie były odniesieniami ale bardziej coś ala snapshotem tych danych w konkretnym momencie. Załatwiało to problem w przypadku edycji tych danych, no i przed wystawieniem można je było edytować.

Jednocześnie (nawiązując do głównego pytania w tym wątku) wystarczy zapisać do logów, że dany user wprowadził zmianę danych adresowych kontrahenta, poprzedni adres miał ID=324, po zmianie mamy adres o ID=1833. Mając tylko taką informację właściwie wiemy wszystko - kto zmienił, kiedy, z czego i na co. A jednocześnie w logu za wiele trzymać nie musimy.

No ja poszedłem w tą stronę, ale z zapisem do tabel historycznych aby user na froncie mógł sobie w razie czego przywrócić. Jak to będize w logach, to tylko admin/programista będzie w stanie wyłuskać te informacje.

0
.andy napisał(a):

Nie. Ja to widzę tak, że w momencie persystencji np. Kontrahenta pobierasz jego obecną wartość z bazy i próbujesz zapisać to co prześle użytkownik. Jak operacja się powiedzie, to pobraną z bazy wersję sprzed zapisu zapisujesz do tabelki Kontrahent Historia czy jakoś tak.

Nie neguje to chyba jednak możliwości stworzenia jednej tabeli dla wszystkich, a tylko za pomocą np kilku DropDownList zawężać wyniki na zasadzie filtrów?

Do serwisu który robi persystencję pewnie musiałaby spływać taka informacja - no. id użytkownika. Czyli ktoś klikając zapisz rekord strzela do backendu przekazując zmieniony rekord i m.in. id osoby, która go zmieniła.

A co myślisz, by każdy użytkownik miał swoją tabelę, której ostatecznie (będąc sumą lub wskaźnikiem wartości wspólnej) wartości łączyłyby się w jedną dla głównego obserwatora (kierownik/manager)?

Nie znam się ale się wypowiem :D Wydaje mi się że przy kliknięciu edycja na rekordzie powinna być robiona jednak blokada tego rekordu na jakiś czas, bo inaczej mogło by dojść do niespodziewanych efektów, czyli handlowiec edytuje firmę w wersji 1.5, zmienia dane i chce kliknąć zapisz a w tym samym czasie kolejny handlowiec też klika zapisz.

<- pomysł z oddzielnymi tabelami?

1

A co myślisz, by każdy użytkownik miał swoją tabelę, której ostatecznie (będąc sumą) wartości łączyłyby się w jedną dla głównego obserwatora (kierownik/manager)?

Tutaj widzę potencjalny problem w postaci rozjazdów między poszczególnymi operatorami. Jak masz jedną tabelę to łatwiej jest kontrolować czy np. zrobić lock na konkretnym kontrahencie, który jest w danej chwili przez kogoś poprawiany. Oczywiście - przy wielu tabelach też da się takie coś zrobić, ale jest to zadanie bardziej skomplikowane i potencjalnie dające dziwne problemy.

0
cerrato napisał(a):

Tutaj widzę potencjalny problem w postaci rozjazdów między poszczególnymi operatorami. Jak masz jedną tabelę to łatwiej jest kontrolować czy np. zrobić lock na konkretnym kontrahencie, który jest w danej chwili przez kogoś poprawiany. Oczywiście - przy wielu tabelach też da się takie coś zrobić, ale jest to zadanie bardziej skomplikowane i potencjalnie dające dziwne problemy.

Nie byłoby chyba problemu gdyby wymusić na użytkownikach operacje na innych danych. W sumie gdyby tabela obserwatora zawierała informację tylko o jednym wybranym "kontrahencie" lub wszystkich na raz to problemu nie powinno być wcale?

0

No ale pytanie jest inne - co chcesz osiągnąć? Bo tutaj mam wrażenie, że kładziesz mocny nacisk na łatwy dostęp do wartości historycznych i wprowadzonych zmian kosztem utrudnienia "normalnego" przeglądania. W sensie (a jeśli źle zrozumiałem zamysł, to wyjaśnij proszę, jak to ma działać) że żeby wyświetlić aktualną wartość jakiegoś pola, to jakiś "główny widok" przeszukuje tabele ze zmianami (jedna dla każdego usera/operatora), potem ustala ostateczną wartość określonej pozycji i ją pokazuje. Czy inaczej to widzisz?

No i tak w ogóle - wyjaśnij, jaki jest zysk na tworzeniu X tabel ze zmianami - tak, aby każdy user miał swoją prywatną. Czemu nie wrzucić tego do jednej tabeli w postaci w stylu: ID | data zmiany | operator | rodzaj zmiany | wartość poprzednia | wartość docelowa

0

@cerrato: Zapis samych danych odbywać miałby się w oddzielnych tabelach (porównane/łączone w jednej - głównego obserwatora), ale zmiany (logi) zapisywane by były w jednej i tej samej.

1

A co myślisz, by każdy użytkownik miał swoją tabelę, której ostatecznie (będąc sumą lub wskaźnikiem wartości wspólnej) wartości łączyłyby się w jedną dla głównego obserwatora (kierownik/manager)?

Odpowiedz proszę na pytanie (nie piszę tego złośliwie, ale po porostu totalnie nie rozumiem idei takiego scenariusza) - czemu ma służyć takie rozbicie? Co dzięki temu osiągniesz/co będzie lepiej działać?

0

@Neosphoros:

Nie neguje to chyba jednak możliwości stworzenia jednej tabeli dla wszystkich, a tylko za pomocą np kilku DropDownList zawężać wyniki na zasadzie filtrów?

Nie.

A co myślisz, by każdy użytkownik miał swoją tabelę, której ostatecznie (będąc sumą lub wskaźnikiem wartości wspólnej) wartości łączyłyby się w jedną dla głównego obserwatora (kierownik/manager)?

Tak się nie robi.

<- pomysł z oddzielnymi tabelami?

No nie. Masz powiedzmy tabelkę Kontrahent i tabelkę Kontrahent Historia, który trzyma zmiany aka dane historyczne dla niej.

0

@cerrato: Weźmy za przykład np tworzenie kosztorysu lub listy założeń (który jako składowa byłby częścią większego projektu i związanych z nim założeń) pomijając bazy danych do których musiałby się on odnosić. Do takiego kosztorysu wprowadzać zmiany (jako propozycje) mogłoby kilku użytkowników. W związku z tym zamieszczenie wszystkich możliwych zmian w jednej tabeli byłoby chyba bardzo chaotyczne i trudne w kontroli tym bardziej, że istniałoby zagrożenie, że dane mogłoby (chyba) wpływać na siebie. W związku z tym najlepszym (najbezpieczniejszym i najłatwiejszym w kontroli) rozwiązaniem byłoby (chyba) utworzenie kilku tabel jako (propozycji) kosztorysów (a ostatecznie nawet i nie tylko), a dla obserwatora - jednej jako porównawczej (lub takiej z której będzie mógł wybrać pasujące mu wartości). BD z logami byłaby w takim wypadku jedną tabelą dla wszystkich użytkowników, bo i tak za pomocą filtrów znalazłby to co by chciał.

0

wprowadzać zmiany (jako propozycje) mogłoby kilku użytkowników

No to teraz mi się narzuca inne rozwiązanie - zrobić listę zmian oczekujących na akceptację, a potem (po akceptacji przez odpowiednią osobę) mamy dopiero wrzucenie do głównej tabeli/oferty.

W związku z tym zamieszczenie wszystkich możliwych zmian w jednej tabeli byłoby chyba bardzo chaotyczne i trudne w kontroli tym bardziej, że istniałoby zagrożenie, że dane mogłoby (chyba) wpływać na siebie

Nie uważam tak, wręcz przeciwnie - moim zdaniem większe zamieszanie powstanie przy rozbiciu danych na wiele tabel. Tak, jak pisałem wcześniej - robisz jedną tabelę (wtedy podałem przykład w postaci ID | data zmiany | operator | rodzaj zmiany | wartość poprzednia | wartość docelowa) i w niej filtrujesz sobie to, co jest Ci potrzebne do szczęścia. Nie ma opcji, żeby się coś pomieszało - nigdy nie zrobią się 2 zapisy jednocześnie, nawet jakby w tej samej milisekundzie dwóch operatorów kliknęło "zapisz" to zawsze jeden zapis zostanie wprowadzony do bazy wcześniej, więc dostanie niższe ID.

1

W związku z tym zamieszczenie wszystkich możliwych zmian w jednej tabeli byłoby chyba bardzo chaotyczne i trudne w kontroli tym bardziej, że istniałoby zagrożenie, że dane mogłoby (chyba) wpływać na siebie.

No nie? Przecież każda zmiana to rekord w tabeli historycznej czy jak ja tam nazwiemy i id tego rekordu jest inkrementowane, wiec nie ma tu takiego zagrożenia.

@Neosphoros ja bym zaczął na twoim miejscu od konkretnej analizy - w tym przypadku z jakimi obiektami masz do czynienia oraz co z nimi można robić, co nie można, jak się mają zachowywać itp.

Brakuje tutaj analizy która odpowie na większość pytań.

3

Tabela typu XHistory + triggerek który sam będzie zapisywał każdą zmianę/dodanie oraz informacje o tym kto i kiedy.

Wady takie że trzeba pamiętać o aktualizowaniu triggera, no ale to typowe problemy programowania w bazie danych, ktorego na ogól unikałbym, ale do tabelek historycznych mi pasuje.

A, no i średnio z testowaniem.

0

A jaka baza? Bo jak jakaś porządna, to audyt czy inne change data capture można włączyć tak po prostu i nie trzeba kombinować samemu z triggerami.

1 użytkowników online, w tym zalogowanych: 0, gości: 1