Design Multi-Module Logging Framework
Design a logging framework for three application modules: "MODULE1", "MODULE2", and "MODULE3".
A module submits a log with a sequence number, destination, log level, and activity data. The framework places every accepted log in a shared buffer and writes it to the selected destination as a stream.
The supported logging destinations are "FILE" and "TOOL". A log receives an acknowledgement only after it has been written successfully.
The framework must also support retrieving logs by destination, module, log level, and an inclusive sequence-number range.
Class Definition
MultiModuleLoggingFramework()
- The framework starts with an empty buffer and no written logs.
- The framework supports both "FILE" and "TOOL" destinations.
Method Signatures
Submit an Activity Log
String logActivity(long sequenceNumber, String moduleName, String destinationType, String logLevel, String logData)
sequenceNumber is a positive identifier supplied by the module.
sequenceNumber must be unique across all logs in the framework.
- Sequence numbers do not need to be consecutive or submitted in increasing order.
moduleName must be "MODULE1", "MODULE2", or "MODULE3".
destinationType must be "FILE" or "TOOL".
logLevel must be "INFO", "WARNING", or "ERROR".
logData contains the activity information to be logged.
It doesn't contain comma character for consistency.
- After the log has been written successfully, return "ACK,sequenceNumber".
- Return "REJECTED" if any input is invalid or the sequence number has already been used.
- A rejected log is not written to any destination.
Fetch Logs
List<String> getLogs(String destinationType, String moduleName, String logLevel, long minimumSequenceNumber, long maximumSequenceNumber)
- Return logs whose sequence numbers are between
minimumSequenceNumber and maximumSequenceNumber, inclusive.
- Use "FILE" or "TOOL" to filter by destination. Use "ALL" to include both destinations.
- Use a supported module name to filter by module. Use "ALL" to include every module.
- Use a supported log level to filter by level. Use "ALL" to include every log level.
- A log is returned only when it satisfies every supplied filter.
- Return matching logs in increasing sequence number order.
- Represent each returned log as "sequenceNumber,destinationType,moduleName,logLevel,logData".
- Return an empty list when no log matches the filters.
Logging Rules
- Every accepted sequence number must be unique.
- Each accepted log must be written exactly once.
- An acknowledgement is returned only after the corresponding log has been written.
- Logs may be submitted in any sequence-number order.
- Rejected logs must not appear in retrieval results.
- Retrieval results are always sorted by increasing sequence number.
- Commas in
logData are preserved as part of the activity data.
Constraints
1 ≤ sequenceNumber ≤ 1,000,000,000
moduleName is "MODULE1", "MODULE2", or "MODULE3".
destinationType is "FILE" or "TOOL" when submitting a log.
destinationType is "FILE", "TOOL", or "ALL" when fetching logs.
logLevel is "INFO", "WARNING", or "ERROR" when submitting a log.
logLevel may also be "ALL" when fetching logs.
1 ≤ logData.length() ≤ 10,000
1 ≤ minimumSequenceNumber ≤ maximumSequenceNumber ≤ 1,000,000,000
- At most
100,000 logs are submitted to one framework instance.
Example 1
MultiModuleLoggingFramework()
Output: A logging framework with no written logs.
logActivity(sequenceNumber = 205, moduleName = "MODULE2", destinationType = "FILE", logLevel = "INFO", logData = "Invoice generated")
Output: "ACK,205"
logActivity(sequenceNumber = 110, moduleName = "MODULE1", destinationType = "TOOL", logLevel = "ERROR", logData = "Payment timed out")
Output: "ACK,110"
getLogs(destinationType = "FILE", moduleName = "ALL", logLevel = "ALL", minimumSequenceNumber = 1, maximumSequenceNumber = 500)
Output: ["205,FILE,MODULE2,INFO,Invoice generated"]
Only the log written to the "FILE" destination is returned.
Example 2
MultiModuleLoggingFramework()
Output: A logging framework with no written logs.
logActivity(sequenceNumber = 72, moduleName = "MODULE3", destinationType = "TOOL", logLevel = "WARNING", logData = "Cache is nearly full")
Output: "ACK,72"
logActivity(sequenceNumber = 24, moduleName = "MODULE3", destinationType = "TOOL", logLevel = "INFO", logData = "Cache refreshed")
Output: "ACK,24"
logActivity(sequenceNumber = 95, moduleName = "MODULE1", destinationType = "FILE", logLevel = "WARNING", logData = "Login attempt delayed")
Output: "ACK,95"
getLogs(destinationType = "TOOL", moduleName = "MODULE3", logLevel = "ALL", minimumSequenceNumber = 1, maximumSequenceNumber = 100)
Output: ["24,TOOL,MODULE3,INFO,Cache refreshed", "72,TOOL,MODULE3,WARNING,Cache is nearly full"]
Both matching logs are returned in increasing sequence number order.
Example 3
MultiModuleLoggingFramework()
Output: A logging framework with no written logs.
logActivity(sequenceNumber = 45, moduleName = "MODULE2", destinationType = "FILE", logLevel = "ERROR", logData = "Report generation failed")
Output: "ACK,45"
logActivity(sequenceNumber = 45, moduleName = "MODULE1", destinationType = "TOOL", logLevel = "INFO", logData = "User signed in")
Output: "REJECTED"
getLogs(destinationType = "ALL", moduleName = "ALL", logLevel = "ERROR", minimumSequenceNumber = 1, maximumSequenceNumber = 100)
Output: ["45,FILE,MODULE2,ERROR,Report generation failed"]
The second log is rejected because sequence number 45 was already used.