Last active
July 21, 2019 07:04
-
-
Save zaydek-old/7bfa78db7934fe272b37f3bafe6e8377 to your computer and use it in GitHub Desktop.
Proof-of-concept for SQL-driven logging. You can like this tweet for updates: https://twitter.com/username_ZAYDEK/status/1114827120524419073
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
bash$ pg_ctl -D /usr/local/var/postgres start ## init postgres | |
bash$ psql -d postgres ## connect to postgres | |
psql# create database logger; -- create a database named "logger" | |
psql# begin; -- start a transaction | |
psql# \i log.sql -- load database | |
psql# commit; -- commit the transaction | |
bash$ go run log.go ## run driver program |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package main | |
import ( | |
"database/sql" | |
"encoding/json" | |
"errors" | |
"reflect" | |
"runtime" | |
_ "github.com/lib/pq" | |
) | |
/* | |
* constants | |
*/ | |
const SERVICE_NAME = "log" | |
type Level string | |
const ( | |
INFO = "info" | |
WARN = "warn" | |
FATA = "fata" | |
) | |
/* | |
* JSON | |
*/ | |
var ErrServerError = JSON{"status_code": 500, "status_desc": "server error"} | |
type JSON map[string]interface{} | |
func (j JSON) String() string { | |
data, err := json.MarshalIndent(j, "", "\t") | |
if err != nil { | |
str := ErrServerError.String() | |
return str | |
} | |
return string(data) | |
} | |
/* | |
* logger | |
*/ | |
// stackoverflow.com/questions/7052693 | |
func fn_name(x interface{}) string { | |
return runtime.FuncForPC(reflect.ValueOf(x).Pointer()).Name() | |
} | |
func LogStdout(fn_ptr interface{}, fn_values JSON) { | |
_, db_err := db.Exec(`select log_stdout($1, $2, $3)`, | |
SERVICE_NAME, fn_name(fn_ptr), fn_values.String()) | |
must(db_err) // just for testing | |
} | |
func LogStderr(level string, fn_ptr interface{}, fn_values JSON, err error) { | |
_, db_err := db.Exec(`select log_stderr($1, $2, $3, $4, $5)`, | |
SERVICE_NAME, level, fn_name(fn_ptr), fn_values.String(), err.Error()) | |
must(db_err) // just for testing | |
} | |
/* | |
* example_fns | |
*/ | |
func example_fn1(a, b int, c string) { | |
LogStdout(example_fn1, JSON{"a": a, "b": b, "c": c}) | |
} | |
func example_fn2(a, b int, c string) { | |
err := errors.New("something went wrong") | |
LogStderr(INFO, example_fn2, JSON{"a": a, "b": b, "c": c}, err) | |
} | |
/* | |
* main | |
*/ | |
var db *sql.DB | |
func must(err error) { | |
if err != nil { | |
panic(err) | |
} | |
} | |
func must_open(conn_str string) *sql.DB { | |
postgres, err := sql.Open("postgres", conn_str) | |
must(err) | |
err = postgres.Ping() | |
must(err) | |
return postgres | |
} | |
func main() { | |
db = must_open("postgres://zaydek@localhost/logger?sslmode=disable") | |
defer db.Close() | |
example_fn1(1, 2, "hello, world!") | |
example_fn2(1, 2, "hello, world!") | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
create extension pgcrypto; | |
/* | |
* helpers | |
*/ | |
create table levels (level text primary key); | |
insert into levels (level) values ('info'), ('warn'), ('fata'); | |
/* | |
* tables | |
*/ | |
create table stdout ( | |
id text primary key default replace(gen_random_uuid()::text, '-', '') unique, | |
timestamp timestamptz not null default now(), | |
service_name text not null, | |
fn_name text not null, | |
fn_values jsonb); | |
create table stderr ( | |
id text primary key default replace(gen_random_uuid()::text, '-', '') unique, | |
timestamp timestamptz not null default now(), | |
service_name text not null, | |
level text not null references levels (level), | |
fn_name text not null, | |
fn_values jsonb, | |
err text); | |
/* | |
* functions | |
*/ | |
create function log_stdout(_service_name text, _fn_name text, _fn_values jsonb, out _id text) as $$ | |
begin | |
insert into stdout (service_name, fn_name, fn_values) | |
values (_service_name, _fn_name, _fn_values) | |
returning id into _id; | |
end; | |
$$ language plpgsql; | |
create function log_stderr(_service_name text, _level text, _fn_name text, _fn_values jsonb, _err text, out _id text) as $$ | |
begin | |
insert into stderr (service_name, level, fn_name, fn_values, err) | |
values (_service_name, _level, _fn_name, _fn_values, _err) | |
returning id into _id; | |
end; | |
$$ language plpgsql; | |
/* | |
* views | |
*/ | |
create view stdout_short as select substr(id, 1, 4) as id, timestamp::timestamp(0), service_name, fn_name, fn_values from stdout; | |
create view stderr_short as select substr(id, 1, 4) as id, timestamp::timestamp(0), service_name, level, fn_name, fn_values, err from stderr; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment