Skip to content

Commit c4f011a

Browse files
Add documentation
1 parent deb86bd commit c4f011a

2 files changed

Lines changed: 546 additions & 0 deletions

File tree

CONTRIBUTORS.md

Lines changed: 210 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,210 @@
1+
# Contributing to loq
2+
3+
Thank you for your interest in contributing to loq! This document provides guidelines and instructions for contributing.
4+
5+
## Code of Conduct
6+
7+
Be kind, respectful, and constructive. We're all here to build something useful together.
8+
9+
## How to Contribute
10+
11+
### Reporting Bugs
12+
13+
1. Check existing issues to avoid duplicates
14+
2. Use the bug report template
15+
3. Include:
16+
- loq version (`loq --version`)
17+
- OS and version
18+
- Steps to reproduce
19+
- Expected vs actual behavior
20+
- Sample log line(s) if relevant
21+
22+
### Suggesting Features
23+
24+
1. Check existing issues/discussions
25+
2. Describe the use case
26+
3. Propose a solution if you have one
27+
28+
### Pull Requests
29+
30+
1. Fork the repository
31+
2. Create a feature branch: `git checkout -b feature/my-feature`
32+
3. Make your changes
33+
4. Add/update tests
34+
5. Ensure all tests pass: `bun test`
35+
6. Ensure coverage stays above 95%: `bun test --coverage`
36+
7. Submit a PR
37+
38+
## Development Setup
39+
40+
```bash
41+
# Clone your fork
42+
git clone https://github.com/YOUR_USERNAME/loq.git
43+
cd loq
44+
45+
# Install dependencies
46+
bun install
47+
48+
# Run tests
49+
bun test
50+
51+
# Run in dev mode
52+
bun run dev
53+
```
54+
55+
## Project Structure
56+
57+
```
58+
src/
59+
├── cli/ # Command-line interface
60+
├── config/ # Configuration loading
61+
├── parser/ # Log parsing
62+
│ └── formats/ # Individual format parsers
63+
├── query/ # Query language
64+
├── output/ # Output formatting
65+
└── utils/ # Utilities
66+
67+
tests/ # Mirror of src/ structure
68+
```
69+
70+
## Adding a New Log Format
71+
72+
### 1. Create the parser
73+
74+
```typescript
75+
// src/parser/formats/myformat.ts
76+
import type { LogEntry, LogParser } from '../types';
77+
78+
export const myFormatParser: LogParser = {
79+
name: 'myformat',
80+
81+
detect(line: string): boolean {
82+
// Fast check - is this line in my format?
83+
return /^MYFORMAT:/.test(line);
84+
},
85+
86+
parse(line: string): LogEntry | null {
87+
const match = line.match(/^MYFORMAT: \[(.+?)\] (\w+) - (.+)$/);
88+
if (!match) return null;
89+
90+
return {
91+
raw: line,
92+
timestamp: match[1],
93+
level: match[2].toLowerCase(),
94+
message: match[3],
95+
fields: {
96+
// Include all parsed fields for querying
97+
timestamp: match[1],
98+
level: match[2],
99+
message: match[3],
100+
},
101+
};
102+
},
103+
};
104+
```
105+
106+
### 2. Register the parser
107+
108+
```typescript
109+
// src/parser/auto-detect.ts
110+
import { myFormatParser } from './formats/myformat';
111+
112+
const builtinParsers: LogParser[] = [
113+
jsonParser,
114+
myFormatParser, // Add here - order matters for detection
115+
apacheParser,
116+
// ...
117+
];
118+
```
119+
120+
### 3. Add tests
121+
122+
```typescript
123+
// tests/parsers/myformat.test.ts
124+
import { describe, expect, test } from 'bun:test';
125+
import { myFormatParser } from '../../src/parser/formats/myformat';
126+
127+
describe('MyFormat Parser', () => {
128+
describe('detect', () => {
129+
test('detects valid format', () => {
130+
expect(myFormatParser.detect('MYFORMAT: [2024-01-01] INFO - test')).toBe(true);
131+
});
132+
133+
test('rejects other formats', () => {
134+
expect(myFormatParser.detect('{"level":"info"}')).toBe(false);
135+
});
136+
});
137+
138+
describe('parse', () => {
139+
test('parses correctly', () => {
140+
const result = myFormatParser.parse('MYFORMAT: [2024-01-01] ERROR - Something failed');
141+
expect(result).not.toBeNull();
142+
expect(result!.timestamp).toBe('2024-01-01');
143+
expect(result!.level).toBe('error');
144+
expect(result!.message).toBe('Something failed');
145+
});
146+
147+
test('returns null for invalid line', () => {
148+
expect(myFormatParser.parse('invalid')).toBeNull();
149+
});
150+
});
151+
});
152+
```
153+
154+
## Coding Guidelines
155+
156+
### TypeScript
157+
158+
- Use strict mode
159+
- Prefer explicit types for public APIs
160+
- Use `type` imports where possible
161+
162+
### Testing
163+
164+
- Aim for 95%+ coverage
165+
- Test both success and failure cases
166+
- Use descriptive test names
167+
- Group related tests with `describe()`
168+
169+
### Performance
170+
171+
- Parser `detect()` should be fast (regex test, not full parse)
172+
- Stream large files, don't load into memory
173+
- Avoid unnecessary allocations in hot paths
174+
175+
### Error Handling
176+
177+
- Don't crash on invalid input
178+
- Return `null` from parsers for non-matching lines
179+
- Log warnings for config issues, don't fail
180+
181+
## Commit Messages
182+
183+
Use conventional commits:
184+
185+
```
186+
feat: add support for Docker log format
187+
fix: handle missing timestamp in syslog
188+
docs: update README with new examples
189+
test: add coverage for edge cases
190+
refactor: simplify query executor
191+
```
192+
193+
## Release Process
194+
195+
Releases are automated via GitHub Actions when a tag is pushed:
196+
197+
```bash
198+
git tag v0.2.0
199+
git push origin v0.2.0
200+
```
201+
202+
## Contributors
203+
204+
Thanks to everyone who has contributed to loq!
205+
206+
<!-- Add your name here when you contribute -->
207+
208+
---
209+
210+
Questions? Open an issue or discussion!

0 commit comments

Comments
 (0)