Project 4: Logging Library
Build a logging library with a clean C API, levels, and safe formatting.
Quick Reference
| Attribute | Value |
|---|---|
| Difficulty | Beginner |
| Time Estimate | 1 week |
| Language | C |
| Prerequisites | Variadic functions, stdio |
| Key Topics | API ergonomics, error handling, safety |
1. Learning Objectives
By completing this project, you will:
- Design a minimal, stable logging API.
- Implement log levels and output targets.
- Ensure thread-safe or documented non-thread-safe behavior.
- Prevent format string misuse.
2. Theoretical Foundation
2.1 Core Concepts
- Log levels: INFO, WARN, ERROR, DEBUG for filtering.
- Variadic APIs:
printf-style formatting. - Thread safety: Global state requires locking or clear docs.
2.2 Why This Matters
Logging sits at module boundaries. A safe, predictable logging API reduces debugging time and avoids format-string vulnerabilities.
2.3 Historical Context / Background
Many C projects roll custom logging libraries with inconsistent APIs. This project focuses on clarity and safety.
2.4 Common Misconceptions
- “printf is safe”: Format strings can be exploited.
- “Global state is fine”: It can break in multi-threaded contexts.
3. Project Specification
3.1 What You Will Build
A logging library with:
log_init,log_set_level,log_set_outputlog_info,log_warn,log_error,log_debug- Optional structured fields
3.2 Functional Requirements
- Support multiple log levels.
- Print timestamp and level.
- Allow output to file or stderr.
- Provide a clean header API.
3.3 Non-Functional Requirements
- Safety: Avoid format string vulnerabilities.
- Usability: Clear, simple API.
- Reliability: Flush logs on crash.
3.4 Example Usage / Output
log_init(LOG_INFO);
log_info("starting server on %s:%d", host, port);
log_error("failed to bind: %s", strerror(errno));
3.5 Real World Outcome
You have a reusable logging library that makes API boundaries clearer and debugging easier across multiple modules.
4. Solution Architecture
4.1 High-Level Design
log API -> formatter -> output sink (stderr/file)
4.2 Key Components
| Component | Responsibility | Key Decisions |
|---|---|---|
| Logger state | Level, output | Global vs handle |
| Formatter | Build log lines | Timestamp + level |
| Sink | Write output | stderr or file |
4.3 Data Structures
typedef enum { LOG_DEBUG, LOG_INFO, LOG_WARN, LOG_ERROR } LogLevel;
typedef struct {
LogLevel level;
FILE *out;
} LogConfig;
4.4 Algorithm Overview
Key Algorithm: Log function
- Compare level to threshold.
- Format timestamp and prefix.
vfprintfmessage.- Flush output.
Complexity Analysis:
- Time: O(n) message length
- Space: O(1)
5. Implementation Guide
5.1 Development Environment Setup
cc -Wall -Wextra -O2 -g -o test_log test_log.c log.c
5.2 Project Structure
loglib/
├── src/
│ ├── log.c
│ └── log.h
├── tests/
│ └── test_log.c
└── README.md
5.3 The Core Question You’re Answering
“How do I expose a logging API that is safe, consistent, and easy to use?”
5.4 Concepts You Must Understand First
Stop and research these before coding:
- Variadic functions
- How does
va_listwork?
- How does
- Thread safety
- What happens if multiple threads log?
- Format string risks
- Why should format strings be static?
5.5 Questions to Guide Your Design
Before implementing, think through these:
- Will you use a global logger or per-instance handle?
- Should users be able to set a custom output callback?
- How will you handle logging from signal handlers?
5.6 Thinking Exercise
Format Strings
What happens if a user passes untrusted data as the format string? How do you prevent that?
5.7 The Interview Questions They’ll Ask
Prepare to answer these:
- “How do variadic functions work in C?”
- “What is a format string vulnerability?”
- “How do you make logging thread-safe?”
5.8 Hints in Layers
Hint 1: Start with stderr logging Skip files at first.
Hint 2: Add log levels Filter by numeric level.
Hint 3: Add output callback Allow user-defined sinks.
5.9 Books That Will Help
| Topic | Book | Chapter |
|---|---|---|
| Variadic APIs | “The C Programming Language” | Ch. 7 |
| Defensive APIs | “Code Complete” | Ch. 8 |
5.10 Implementation Phases
Phase 1: Foundation (2-3 days)
Goals:
- Basic logging to stderr
Tasks:
- Implement
log_infoandlog_error.
Checkpoint: Logs print with prefix.
Phase 2: Core Functionality (2-3 days)
Goals:
- Levels and formatting
Tasks:
- Add level filtering.
- Add timestamps.
Checkpoint: Only level >= threshold prints.
Phase 3: Polish & Edge Cases (2-3 days)
Goals:
- Output selection
Tasks:
- Add file output.
- Add custom sink callback.
Checkpoint: File logging works.
5.11 Key Implementation Decisions
| Decision | Options | Recommendation | Rationale |
|---|---|---|---|
| State | Global vs handle | Global | Simpler for beginners |
| Thread safety | None vs mutex | Documented non-thread-safe | Keep scope clear |
6. Testing Strategy
6.1 Test Categories
| Category | Purpose | Examples |
|---|---|---|
| Unit Tests | Format output | Expected prefixes |
| Integration Tests | File output | Writes to file |
| Edge Cases | Null output | Errors |
6.2 Critical Test Cases
- Level filtering: Lower levels suppressed.
- File output: Logs written to file.
- Long messages: Truncation handled.
6.3 Test Data
"test message"
7. Common Pitfalls & Debugging
7.1 Frequent Mistakes
| Pitfall | Symptom | Solution |
|---|---|---|
| Untrusted format string | Security risk | Require literal format strings |
| Missing flush | Logs not visible | fflush after write |
| Global state races | Garbled logs | Use mutex or document |
7.2 Debugging Strategies
- Compare log output against expected golden file.
- Add unit tests for formatting.
7.3 Performance Traps
Formatting timestamps on every call can be expensive; cache if needed.
8. Extensions & Challenges
8.1 Beginner Extensions
- Add colored output.
- Add log file rotation.
8.2 Intermediate Extensions
- Add JSON log format.
- Add thread-safe logging.
8.3 Advanced Extensions
- Async logging with a queue.
- Structured fields with key/value pairs.
9. Real-World Connections
9.1 Industry Applications
- Servers: Structured logs for observability.
- Embedded systems: Lightweight logging for debug.
9.2 Related Open Source Projects
- log.c: Minimal logging library patterns.
9.3 Interview Relevance
API design and variadic functions are common system questions.
10. Resources
10.1 Essential Reading
- “The C Programming Language” - Ch. 7
- “Code Complete” - Ch. 8
10.2 Video Resources
- C variadic function tutorials
10.3 Tools & Documentation
man 3 vfprintf: Variadic formatting
10.4 Related Projects in This Series
- JSON Parser: Structured output logging.
- libhttp-lite: Server logging API.
11. Self-Assessment Checklist
11.1 Understanding
- I can explain variadic functions.
- I can design log levels.
- I can avoid format string risks.
11.2 Implementation
- Logs print correctly.
- File output works.
- API is consistent.
11.3 Growth
- I can add thread safety.
- I can explain this project in an interview.
12. Submission / Completion Criteria
Minimum Viable Completion:
- Basic logging with levels.
Full Completion:
- File output and timestamps.
Excellence (Going Above & Beyond):
- Async logging and structured output.
This guide was generated from SPRINT_4_BOUNDARIES_INTERFACES_PROJECTS.md. For the complete learning path, see the parent directory.