Skip to content

vpkgs/slog

Folders and files

NameName
Last commit message
Last commit date

Latest commit

9b0afca · Sep 7, 2022

History

21 Commits
Jul 4, 2022
Jul 4, 2022
Jul 9, 2022
Aug 3, 2022
Jul 4, 2022
Jul 9, 2022
Sep 7, 2022
Aug 27, 2022
Jul 9, 2022
Jul 4, 2022
Jul 9, 2022
Jul 9, 2022
Aug 3, 2022
Aug 3, 2022
Aug 3, 2022

Repository files navigation

A Simple Logging library for V

Install

v install --git https://github.com/vpkgs/slog.git

Usage

Simple

import slog
import os

fn main() {
	ofilename := os.real_path(os.join_path(os.dir(@FILE), 'logfile'))
	slog.init_with_default_logger(ofilename)

	slog.err(@MOD, 'Warning here')
	slog.warn(@MOD, 'Warning here')
	slog.info(@MOD, 'Warning here')
	slog.debug(@MOD, 'Warning here') // no output as `level` is `.info`
	slog.trace(@MOD, 'Warning here') // no output as `level` is `.info`
}

If you need module info in log output

import slog
import os

// Really want to generate following template by macro as `@MOD` value changes, or ...
fn err(msg string) {
	slog.log(.error, @MOD, msg)
}
fn warn(msg string) {
	slog.log(.warn, @MOD, msg)
}
fn info(msg string) {
	slog.log(.info, @MOD, msg)
}
fn debug(msg string) {
	slog.log(.debug, @MOD, msg)
}
fn trace(msg string) {
	slog.log(.trace, @MOD, msg)
}

fn main() {
	ofilename := os.real_path(os.join_path(os.dir(@FILE), 'logfile'))
	mut logger := slog.init_with_default_logger(ofilename)
	// slog.set_max_level(.info)
	logger.set_level_from_default_env() // value of "V_LOG" is used
	logger.set_level_from_envvar("YOUR_ENVVAR") // value of "YOUR_ENVVAR" is used

	err('Warning here')
	warn('Warning here')
	info('Warning here')
	debug('Warning here') // no output as `level` is `.info`
	trace('Warning here') // no output as `level` is `.info`
}

or

// in your module
import slog

fn err(tag string, msg string) {
	slog.log(.error, tag, msg)
}
fn warn(tag string, msg string) {
	slog.log(.warn, tag, msg)
}
fn info(tag string, msg string) {
	slog.log(.info, tag, msg)
}
fn debug(tag string, msg string) {
	slog.log(.debug, tag, msg)
}
fn trace(tag string, msg string) {
	slog.log(.trace, tag, msg)
}

// then use
fname := os.real_path(os.join_path(os.dir(@FILE), 'logfile'))
slog.init_with_default_logger(fname) // should be called only once
slog.set_max_level(.trace)
//
error(@FILE, 'error')
warn(@FILE, 'warn')
info(@FILE, 'info')
debug(@FILE, 'debug')
trace(@FILE, 'trace')

Custom Logger

See DefaultLogger implementation.

// It's easy to do WebSocket, http or ... anything in same way.
import slog {Level, BaseLogger}
import time

fn main() {
	logger := init_logger(level: .trace)
	go logger.collect()

	slog.info('it works!!')
}

type Msg = Item | Cmd
enum Cmd {
	close
}
struct Item {
	level Level
	target string
	msg string
	time time.Time
}
pub struct CustomLoggger {
	BaseLogger
	msg_ch chan Msg
}

[params]
pub struct CustomLogggerOpt {
pub:
	level Level = Level.info
}
pub fn init_logger(opt CustomLogggerOpt) &CustomLoggger {
	mut log := &CustomLoggger {
		msg_ch: chan Msg {cap: 20}
	}
	slog.set_logger(log)
	slog.set_max_level(opt.level)
	return log
}

pub fn (lg &CustomLoggger) log(lv Level, target string, msg string) {
	timestamp := time.now()
	lg.msg_ch <- Item {
		level: lv
		target: target
		msg: msg
		time: timestamp
	}
}

pub fn (lg &CustomLoggger) close() {
	lg.msg_ch <- Cmd.close
}

pub fn (lg &CustomLoggger) collect() {
	for {
		msg := <- lg.msg_ch
		match msg {
			Item {
				println(msg)
			}
			Cmd {
				lg.close()
				break
			}
		}
	}
}

Environment Variable

Using envvar, we can avoid hard coding log level.

How to use

The following code

// set 'trace,net.websocket=warn,mylib=trace' as value of `V_LOG`. It's not need to be hardcoded. set at terminal instead...
os.setenv(slog.default_env, 'trace,net.websocket=warn,mylib=trace', false) // `slog.default_env` => 'V_LOG'
mut logger := init_with_default_logger('myfile')
logger.set_level_from_default_env()
// logger.set_level_from_envvar("YOUR_ENVVAR") // if you prefer to use other envvar

is equivalent to

mut logger := init_with_default_logger('myfile')
set_max_level(.trace)
logger.lv_map['net.websocket'] = .warn
logger.lv_map['mylib'] = .trace

Motivation

V's log has big restriction. it have to be mutable when log things.

Rust's tracing is very easy to use, so I used tracing as main reference.

Contribution

Feature Request

If you want new features:

  • You can create a PR as a discussion (I may merge, but may not.).
  • You can create an ISSUE before submit a PR, to make sure the PR will be merged (cannot promise 100%).

Bugfix

Plz create Pull Requests