Từ quan điểm thiết kế, các thực hành tốt nhất để đăng nhập là gì? [đóng cửa]


11

Tôi muốn thêm đăng nhập vào một ứng dụng tôi hiện đang làm việc. Tôi đã thêm đăng nhập trước đây, đó không phải là một vấn đề ở đây.

Nhưng từ góc độ thiết kế trong một ngôn ngữ hướng đối tượng, các thực tiễn tốt nhất để ghi nhật ký theo OOP và các mẫu là gì?

Lưu ý: Tôi hiện đang làm điều này trong C #, vì vậy các ví dụ trong C # rõ ràng rất đáng hoan nghênh. Tôi cũng muốn xem các ví dụ trong Java và Ruby.


Chỉnh sửa: Tôi đang sử dụng log4net. Tôi chỉ không biết cách tốt nhất để cắm nó vào.

Câu trả lời:


6

Cách thực hành tốt nhất mà tôi muốn giới thiệu là sử dụng log4j thay vì tự lăn. (Đã được chuyển từ Java sang cả C # và Ruby, vì vậy nó được áp dụng cho cả 3 ngôn ngữ mà bạn quan tâm.)

Nếu bạn đọc qua trang hướng dẫn đó, bạn sẽ khám phá ra một số thực tiễn tốt nhất khác. Chẳng hạn như nhẹ, có thể định cấu hình bên ngoài ứng dụng của bạn, có thể bật và tắt ghi nhật ký cho các phần khác nhau của ứng dụng một cách độc lập, v.v.


5

Nơi tôi làm việc, chúng tôi viết rất nhiều ứng dụng máy tính để bàn .NET. Chúng tôi thường triển khai 2 sự kiện trong các thành phần của mình, một sự kiện để ghi thông tin và sự kiện khác để ghi nhật ký ngoại lệ (mặc dù chúng tôi thường để ngoại lệ nổi lên thay vì tăng sự kiện riêng biệt. Điều này phụ thuộc vào tình huống). Sử dụng kiến ​​trúc này, không có thư viện nào của chúng tôi cần biết cách ghi nhật ký được thực hiện hoặc cách thông tin được sử dụng, lưu trữ hoặc xử lý. Sau đó, chúng tôi có ứng dụng xử lý các sự kiện đăng nhập theo cách phù hợp với ứng dụng đó. Một số năm trước kiến ​​trúc này đã khiến việc chuyển đổi của chúng tôi từ việc sử dụng ghi nhật ký Thư viện MS sang thành phần ghi nhật ký của BitFactory trở thành một quá trình chuyển đổi rất đơn giản.


+1 để sử dụng mẫu Sự kiện / Người quan sát: thay đổi người quan sát, bạn đã thay đổi việc ghi nhật ký
Matthieu M.


2

Cá nhân, tôi chọn khung đăng nhập của sự lựa chọn (trong trường hợp của tôi, Entlib vì tôi làm việc với .NET) và viết một khía cạnh AOP để ghi nhật ký.

Sau đó, bạn có thể gán bất kỳ phương thức / thuộc tính / lớp / không gian tên nào và thêm ghi nhật ký vào chúng mà không làm lộn xộn nguồn.


Nghe có vẻ rất thú vị, nhưng tôi có bảo lưu về những gì bạn sẽ có thể đăng nhập và thông tin nhật ký sẽ như thế nào (nghĩa là nhiều hơn "công cụ" chỉ là phương pháp). Rất thích xem một ví dụ hoạt động của phương pháp này để xem những gì có thể và không thể được thực hiện. Đặc biệt là khi tôi mới bắt đầu vào một ứng dụng mới và muốn xem tôi có thể mang cái này đến đâu / bao xa.
Marjan Venema

@marjan Venema: Tài liệu sắc nét của bài đăng có một ví dụ về khía cạnh ghi nhật ký nhập / thoát một phương thức. doc.sharpcrafters.com/postsharp/2.0/##PostSharp.chm/html/... trường hợp Trong bài viết sắc sảo, nó dệt mã từ thuộc tính vào nguồn tại thời gian xây dựng, vì vậy nó không ảnh hưởng đến hiệu suất như một số người khác làm.
Steven Evers

1

Hệ thống tôi hiện đang làm việc sử dụng kiến ​​trúc và nhắn tin hướng sự kiện, do đó hầu hết các hành động trong hệ thống của chúng tôi là kết quả của một lệnh và chúng dẫn đến các sự kiện (như các lớp DTO được gửi đi, thay vì một sự kiện ủy nhiệm tiêu chuẩn). Chúng tôi đính kèm xử lý sự kiện với mục đích duy nhất là xử lý đăng nhập. Thiết kế này giúp chúng tôi không lặp lại chính mình và cũng không phải sửa đổi mã hiện có để thêm / thay đổi chức năng.

Đây là một ví dụ về một lớp ghi nhật ký như vậy, xử lý tất cả các sự kiện được ghi lại từ một phần hẹp trong ứng dụng của chúng tôi (những sự kiện liên quan đến một nguồn nội dung cụ thể mà chúng tôi nhập từ).

Tôi không nhất thiết phải nói rằng đây là cách thực hành tốt nhất, vì dường như tôi thay đổi suy nghĩ về những gì và cách đăng nhập thường xuyên - và mỗi khi tôi cần sử dụng nhật ký để chẩn đoán vấn đề, tôi chắc chắn sẽ tìm cách cải thiện thông tin tôi ghi lại.

Tuy nhiên, tôi sẽ nói rằng việc ghi lại thông tin thích hợp (đặc biệt là theo cách Ctrl-F / tìm cách tìm kiếm) là phần quan trọng nhất.

Phần quan trọng thứ hai là lấy mã đăng nhập ra khỏi logic chính của bạn - nó có thể làm cho một phương thức trở nên xấu và dài và bị sai lệch rất nhanh.

public class MctLogger :
    IEventHandler<StoryImported>,
    IEventHandler<StoryScanned>,
    IEventHandler<SourceDirectoryMissing>,
    IEventHandler<SourceDirectoryAccessError>,
    IEventHandler<CannotCreateScannedStoryDirectory>,
    IEventHandler<CannotReadStoryDocument>,
    IEventHandler<StorySkippedPastCutoff>,
    IEventHandler<StorySkippedDuplicateUniqueId>,
    IEventHandler<StorySkippedByFilter>
{

    public void Observe(StoryImported e)
    {
        var log = Slf.LoggerService.GetLogger("RoboChef.Content.Mct.StoryImported");
        log.Info("Story Unique ID: {Story.UniqueId}, Content ID: {ContentId}, Title: {Story.Headline}".SmartFormat(e));
    }

    public void Observe(StoryScanned e)
    {
        var log = Slf.LoggerService.GetLogger("RoboChef.Content.Mct.StoryScanned");
        log.Info("Story Unique ID: {Story.UniqueId}, File: {FilePath}, Title: {Story.Headline}".SmartFormat(e));
    }

    public void Observe(SourceDirectoryMissing e)
    {
        var log = Slf.LoggerService.GetLogger("RoboChef.Content.Mct.SourceDirectoryMissing");
        log.Error("Directory: " + e.Directory);
    }

    public void Observe(SourceDirectoryAccessError e)
    {
        var log = Slf.LoggerService.GetLogger("RoboChef.Content.Mct.SourceDirectoryAccessError");
        log.Error(e.Exception, "Exception: " + e.Exception.Message);
    }

    public void Observe(CannotCreateScannedStoryDirectory e)
    {
        var log = Slf.LoggerService.GetLogger("RoboChef.Content.Mct.CannotCreateScannedStoryDirectory");
        log.Error(e.Exception, "Directory: {Directory}, Exception: {Exception.Message}".SmartFormat(e));
    }

    public void Observe(CannotReadStoryDocument e)
    {
        var log = Slf.LoggerService.GetLogger("RoboChef.Content.Mct.CannotReadStoryDocument");
        if (e.Exception == null) {
            log.Warn("File: {FilePath}".SmartFormat(e));
        }
        else {
            log.Warn(e.Exception, "File: {FilePath}, Exception: {Exception.Message}".SmartFormat(e));
        }
    }

    public void Observe(StorySkippedPastCutoff e)
    {
        var log = Slf.LoggerService.GetLogger("RoboChef.Content.Mct.StorySkippedPastCutoff");
        log.Warn("Story Unique ID: {Story.UniqueId}, File: {FilePath}, Title: {Story.Headline}".SmartFormat(e));
    }

    public void Observe(StorySkippedDuplicateUniqueId e)
    {
        var log = Slf.LoggerService.GetLogger("RoboChef.Content.Mct.StorySkippedDuplicateUniqueId");
        log.Warn("Story Unique ID: {Story.UniqueId}, File: {FilePath}, Title: {Story.Headline}".SmartFormat(e));
    }

    public void Observe(StorySkippedByFilter e)
    {
        var log = Slf.LoggerService.GetLogger("RoboChef.Content.Mct.StorySkippedByFilter");
        log.Warn("Story Unique ID: {Story.UniqueId}, Reason: {Reason}, File: {FilePath}, Title: {Story.Headline}".SmartFormat(e));
    }
}

1

Như những người khác đã nói, sử dụng log4jhoặc log4nethoặc một số khung ghi nhật ký được xây dựng tốt khác.

Tôi có xu hướng thực sự không thích mã đăng nhập theo cách logic kinh doanh. Đó là lý do tại sao tôi sử dụng Log4PostSharp. Điều đó có nghĩa là tôi có thể sử dụng Lập trình hướng đối tượng để chú thích các phương thức như thế này:

[Log(LogLevel.Info, "Counting characters.")]
int CountCharacters(string arg) 
{
    return arg.Length;
}

Hoặc mọi phương thức trong một hội đồng như thế này:

[assembly: Log(AttributeTargetTypes = "*", 
 EntryLevel = LogLevel.Debug, ExitLevel = LogLevel.Debug, 
 ExceptionLevel = LogLevel.Error)]

0

Tôi không chắc chắn nếu có bất kỳ khung nào làm điều này, nhưng từ góc độ thiết kế, tôi sẽ mô hình hóa thông tin cần phải được đăng nhập chủ yếu vào ba loại:

  1. phương pháp theo dõi mức
  2. đăng nhập ngoại lệ
  3. các nhà phát triển thông tin thêm thời gian chạy tin rằng điều đó rất quan trọng để điều tra trong trường hợp thất bại trong thời gian chạy (hoặc bất kỳ hành vi nào liên quan đến tình huống chỉ trong thời gian chạy).

Đối với hai danh mục đầu tiên, khung ghi nhật ký lý tưởng của tôi nên xử lý chúng như một quy trình xây dựng bài đăng và minh bạch cho các nhà phát triển. Sẽ rất tốt nếu khai báo thêm đăng nhập vào các cụm, đại loại như sau:

Trace YourNamespace.* [public methods|constructors]
{  # options
   ignore trivial methods,
   format: "{time stamp}: {method name}({parameter list})",
   condition: "{Context.Instance.UserID in (12432,23432)}",
}

Exception YourNamespace.Program.Main [unhandled exceptions]
{
  format: "{time stamp}: {Context.Instance.UserId} {exception}",
  action: die,  # options are throw, swallow,
}

Đối với danh mục thứ 3, lập trình viên chỉ có thể tạo một hoặc nhiều phương thức "ghi nhật ký" chuyên dụng và tận dụng theo dõi cho danh mục đầu tiên. Các phương thức ghi nhật ký không làm gì khác hơn là phục vụ một điểm còn sơ khai mà quy tắc truy tìm có thể được áp dụng.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.