Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 28 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
name: CI

on:
push:
branches: [ master ]
pull_request:
branches: [ '**' ]
workflow_dispatch:

jobs:
test:
name: Go tests
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4

- name: Set up Go
uses: actions/setup-go@v5
with:
go-version: '1.24.x'
check-latest: true

- name: Download deps
run: go mod download

- name: Run tests
run: make test
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# IDE
.idea

coverage.out
48 changes: 48 additions & 0 deletions .golangci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
run:
timeout: 5m
modules-download-mode: readonly

issues:
exclude-use-default: false
max-same-issues: 0
max-issues-per-linter: 0

linters:
enable:
- govet
- staticcheck
- revive
- errcheck
- gosimple
- ineffassign
- unused
- typecheck
- gofmt
- goimports
- misspell
- gocritic

linters-settings:
revive:
severity: warning
rules:
- name: unused-parameter
- name: unreachable-code
- name: indent-error-flow
- name: exported
- name: blank-imports
- name: var-declaration
- name: if-return

misspell:
locale: US

goimports:
local-prefixes: github.com/tarantool/go-tlog

# Skip linters on example files and any generated code
exclude-rules:
- path: ^_examples/
linters: [revive, staticcheck, govet, gocritic]
- path: \.pb\.go$|_gen\.go$
linters: [all]
14 changes: 14 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# Changelog

All notable changes to this project will be documented in this file.

The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).

## [Unreleased]

### Added

### Changed

### Fixed
25 changes: 25 additions & 0 deletions LICENCE
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
BSD 2-Clause License

Copyright (c) 2025, Tarantool AUTHORS
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.

* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
50 changes: 50 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
# Default Go toolchain
GO ?= go
GOLANGCI_LINT ?= golangci-lint
PKG := github.com/tarantool/go-tlog

.PHONY: all test test-race test-coverage lint fmt tidy examples help

all: test

## Run tests
test:
$(GO) test ./...

## Run tests with race detector
test-race:
$(GO) test -race ./...

## Run tests with coverage
test-coverage:
$(GO) test -covermode=atomic -coverprofile=coverage.out ./...

## Run golangci-lint
lint:
$(GOLANGCI_LINT) run ./...

## Format source code
fmt:
$(GO) fmt ./...

## Tidy go.mod / go.sum
tidy:
$(GO) mod tidy

## Run all _examples to ensure they compile and run without panic
examples:
$(GO) run ./_examples/stdout
$(GO) run ./_examples/stderr >/dev/null 2>&1 || true
$(GO) run ./_examples/file
$(GO) run ./_examples/multi

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
## Run all _examples to ensure they compile and run without panic
examples:
$(GO) run ./_examples/stdout
$(GO) run ./_examples/stderr >/dev/null 2>&1 || true
$(GO) run ./_examples/file
$(GO) run ./_examples/multi


## Show available targets
help:
@echo "Available targets:"
@echo " make test - run tests"
@echo " make test-race - run tests with -race"
@echo " make test-coverage - run tests with coverage"
@echo " make lint - run golangci-lint"
@echo " make fmt - format sources (gofmt)"
@echo " make tidy - go mod tidy"
@echo " make examples - run all examples"
188 changes: 188 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1 +1,189 @@
[![CI](https://github.com/tarantool/go-tlog/actions/workflows/ci.yml/badge.svg)](https://github.com/tarantool/go-tlog/actions/workflows/ci.yml)
[Telegram EN](https://t.me/tarantool)
[Telegram RU](https://t.me/tarantoolru)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some budgets are without images that looks bad. You could copy-paste approach from here:

https://github.com/tarantool/go-tarantool/blob/802aa244d26017a901cf7247119515f346ac8eb6/README.md?plain=1#L5-L10


---

<p href="https://www.tarantool.io">
<img src="https://github.com/tarantool.png" align="right" width=250>
</p>

# go-tlog

`go-tlog` is a lightweight and configurable logging library for Go applications.
It provides structured logging with multiple output destinations, flexible formatting,
and fine-grained log-level control.

---

## Features

- Simple setup via configuration struct
- Text or JSON output formats
- Multiple output targets: **stdout**, **stderr**, **files**
- Log levels: `Trace`, `Debug`, `Info`, `Warn`, `Error`
- Automatic timestamp, source file, and line number
- Stacktrace for errors

---

## Installation

```bash
go get github.com/tarantool/go-tlog@latest
```

Then import:

```go
import "github.com/tarantool/go-tlog"
```

---

## Quick start

```go
package main

import "github.com/tarantool/go-tlog"

func main() {
log, err := tlog.New(tlog.Opts{
Level: tlog.LevelInfo,
Format: tlog.FormatText,
Path: "stdout",
})
if err != nil {
panic(err)
}
defer log.Close()

logger := log.Logger().With(tlog.String("component", "demo"))
logger.Info("service started", "port", 8080)
logger.Error("failed to connect", "err", "timeout")
}
```

Output:

```
2025-11-10T13:30:01+05:00 INFO service started component=demo port=8080
2025-11-10T13:30:01+05:00 ERROR failed to connect err=timeout component=demo stacktrace="..."
```

---

## Configuration

### `type Opts`

```go
type Opts struct {
Level Level // minimal log level
Format Format // FormatText or FormatJSON
Path string // comma-separated outputs: "stdout,/var/log/app.log"
}
```

### Main API

| Function | Description |
|------------------|------------------------------------------|
| `tlog.New(opts)` | Create a new logger |
| `Logger()` | Return the underlying logger for use |
| `Close()` | Flush buffers and close file descriptors |

---

## Log levels

| Level | When to use |
|---------|---------------------------------------------|
| `Trace` | Low-level tracing |
| `Debug` | Debugging information |
| `Info` | Normal operational messages |
| `Warn` | Non-fatal warnings |
| `Error` | Errors and exceptions (includes stacktrace) |

---

## Output formats

| Format | Example |
|--------------|---------------------------------------------------------------|
| `FormatText` | `2025-11-10T13:31:45+05:00 INFO message key=value` |
| `FormatJSON` | `{"time":"...","level":"INFO","msg":"message","key":"value"}` |

---

## Output destinations

You can specify multiple targets separated by commas:

```go
Path: "stdout,/tmp/app.log"
```

Supported targets:

- `stdout`
- `stderr`
- File paths (created automatically if not present)

---

## Examples

Ready-to-run examples are located in the `_examples/` directory:

```
_examples/
├── stdout/
│ └── main.go
├── stderr/
│ └── main.go
├── file/
│ └── main.go
└── multi/
└── main.go
```

Run examples:

```bash
# Example 1 — log to STDOUT in text format
go run ./_examples/stdout

# Example 2 — log to STDERR in JSON format
# Redirect stderr to a file and inspect its contents
go run ./_examples/stderr 2> logs.json
cat logs.json

# Example 3 — log to a file in /tmp directory
# The file will be created automatically if it doesn’t exist
go run ./_examples/file
cat /tmp/tlog_demo/app.log

# Example 4 — log to multiple destinations (stdout + file)
# This writes the same log entry both to console and to /tmp/tlog_multi/app.log
go run ./_examples/multi
cat /tmp/tlog_multi/app.log
```

Each example demonstrates different combinations of Path, Format, and Level,
including how to log to multiple outputs at the same time.

---

## Testing

```bash
go test ./...
```

---

## License

BSD 2-Clause License — see [LICENSE](LICENSE)
27 changes: 27 additions & 0 deletions _examples/file/main.go

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is better to make testable examples in Golang: https://go.dev/blog/examples

  1. This is an idiomatic approach.
  2. The examples will be showed in the documentation.

Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package main

import (
"log/slog"
"os"

"github.com/tarantool/go-tlog"
)

func main() {
_ = os.MkdirAll("/tmp/tlog_demo", 0755)

l, err := tlog.New(tlog.Opts{
Level: tlog.LevelInfo,
Format: tlog.FormatText,
Path: "/tmp/tlog_demo/app.log",
})
if err != nil {
panic(err)
}
defer l.Close()

log := l.Logger().With(slog.String("mode", "file"))
log.Info("logging to file", "path", "/tmp/tlog_demo/app.log")
log.Warn("network delay", "ms", 250)
log.Error("write failed", "err", "disk quota exceeded")
}
Loading