Đặt cược tốt nhất của bạn là làm cho giao diện đơn giản nhất có thể. Hoàn toàn tách biệt giao diện của người dùng đăng nhập từ cách thực hiện ghi nhật ký.
Các mối quan tâm cắt ngang luôn tốn kém để duy trì, vì vậy việc làm mọi thứ phức tạp hơn sẽ khiến bạn ghét cuộc sống.
Một số thư viện chỉ muốn một cái gì đó đơn giản như thế này:
void logDebug(const std::string &msg);
void logWarning(const std::string &msg);
void logError(const std::string &msg);
Họ không nên thêm hoặc chỉ định bất kỳ bối cảnh nhiều hơn. Không ai có thể sử dụng các thông tin anyway, do đó, không qua thiết kế nó.
Nếu bạn bắt đầu thêm nhiều thông tin hơn vào cuộc gọi ghi nhật ký, việc này sẽ khiến việc sử dụng lại mã khách hàng sử dụng nó trở nên khó khăn hơn. Thông thường bạn sẽ thấy bề mặt này khi các thành phần được sử dụng ở các mức trừu tượng khác nhau. Đặc biệt khi một số mã cấp thấp cung cấp thông tin gỡ lỗi chỉ liên quan đến các cấp cao hơn.
Điều này không buộc triển khai ghi nhật ký của bạn (hoặc thậm chí giao diện triển khai ghi nhật ký phù hợp!) Vào bất kỳ thứ gì, vì vậy bạn có thể thay đổi nó bất cứ khi nào.
CẬP NHẬT:
Tức là gắn thẻ, đó là mối quan tâm cấp cao. Tôi sẽ suy đoán rằng nó không thuộc về nhật ký, nhưng đó không phải là ở đây cũng không có ở đó.
Giữ nguyên thông số kỹ thuật ghi nhật ký. Mã cấp thấp không nên cung cấp cho một chiếc xe tải bay mà bạn hoặc người quản lý của bạn đang sử dụng.
Tôi không biết cách bạn chỉ định X
hoặc Y
trong ví dụ của bạn. Làm thế nào bạn làm điều đó là không thực sự rõ ràng từ mô tả chúng tôi được đưa ra. Tôi sẽ chỉ sử dụng một chuỗi để trình diễn, nhưng bạn nên thay thế nó bằng một cái gì đó kiểu an toàn nếu có thể.
Nếu điều này luôn bật, thì chỉ cần có ngữ cảnh cá thể (có thể là biến toàn cầu) có thể phù hợp. Khi bạn đăng nhập, hãy đặt bối cảnh và quên nó đi. Nếu nó chưa bao giờ được thiết lập, hãy ném với định kiến cực đoan. Nếu bạn không thể ném khi nó không được thiết lập, sau đó nó không phải là luôn luôn trên.
void setLoggingContext("X:");
Nếu điều này thay đổi ở mức trừu tượng khác nhau, tôi sẽ xem xét việc thực hiện RAII dựa trên ngăn xếp.
LoggingTag tag("X:");
Tôi không chắc chắn yêu cầu của bạn là gì khi các khung ngăn xếp khác nhau vượt qua các giá trị khác nhau. Tôi có thể thấy nơi đầu hoặc cuối của ngăn xếp sẽ là hợp lý cho các trường hợp sử dụng khác nhau.
void foo() {
LoggingTag tag("X:");
logWarning("foo");
bar();
baz();
}
void bar() {
LoggingTag tag("Y:");
logWarning("bar");
baz();
}
void baz() {
logWarning("baz");
}
Cách này không ảnh hưởng đến cách bạn thêm thư vào nhật ký. Hàm baz
không có ngữ cảnh để chỉ định LoggingTag
. Điều quan trọng là sử dụng logWarning
không biết về thẻ vì lý do này.
Nếu bạn muốn gắn thẻ dựa trên một số loại, bạn có thể làm điều gì đó đơn giản như thế này.
struct LoggingTag {
LoggingTag(const std::string &tag_) : tag(tag_) {}
template<typename T>
static LoggingTag ByType() {
return LoggingTag(typeid(T).name());
}
std::string tag;
};
void foo() {
LoggingTag tag = LogginTag::ByType<int>();
}
này sẽ không lực một người nào đó để sử dụng typeid(T).name()
nếu họ không muốn, nhưng đã cho bạn sự tiện lợi.
Bạn có * thực sự * cần một trình bao bọc không? Hãy tự hỏi. Có thực sự khả năng rằng bạn sẽ chuyển đổi logger của bạn (nhiều lần, có thể) hoặc bạn sẽ sử dụng nhiều khung công tác ghi nhật ký? Viết một wrapper mất tài nguyên (thời gian), và chúng có thể được đưa vào những thứ khác, nếu bạn không * thực sự * cần wrapper. – Xeo
cảm ơn, bạn có thể tin tưởng rằng tôi thực sự làm. Vì mục đích đơn giản, tôi sẵn sàng giải quyết một phiên bản rất nhỏ gọn của nhật ký với tính năng gắn thẻ mà tôi đã đề cập. – Leo