Add dummy server
diff --git a/core/kg/log/log.go b/core/kg/log/log.go
new file mode 100644
index 0000000..84a9987
--- /dev/null
+++ b/core/kg/log/log.go
@@ -0,0 +1,122 @@
+package log
+
+import (
+	"os"
+
+	"go.uber.org/zap"
+	"go.uber.org/zap/zapcore"
+	"gopkg.in/natefinch/lumberjack.v2"
+)
+
+const (
+	// LevelDebug represents very verbose messages for debugging specific issues
+	LevelDebug = "debug"
+	// LevelInfo represents default log level, informational
+	LevelInfo = "info"
+	// LevelWarn represents messages about possible issues
+	LevelWarn = "warn"
+	// LevelError represents messages about things we know are problems
+	LevelError = "error"
+)
+
+// Type and function aliases from zap to limit the libraries scope into our code
+type Field = zapcore.Field
+
+var Int = zap.Int
+var String = zap.String
+var Any = zap.Any
+var Err = zap.Error
+var Time = zap.Time
+var Duration = zap.Duration
+
+// Logger logs messages
+type Logger struct {
+	zap          *zap.Logger
+	consoleLevel zap.AtomicLevel
+	fileLevel    zap.AtomicLevel
+}
+
+// LoggerConfiguration represents configuration of the logger
+type LoggerConfiguration struct {
+	EnableConsole bool
+	ConsoleJSON   bool
+	ConsoleLevel  string
+	EnableFile    bool
+	FileJSON      bool
+	FileLevel     string
+	FileLocation  string
+}
+
+// NewLogger creates new logger
+func NewLogger(config *LoggerConfiguration) *Logger {
+	cores := []zapcore.Core{}
+	logger := &Logger{
+		consoleLevel: zap.NewAtomicLevelAt(getZapLevel(config.ConsoleLevel)),
+		fileLevel:    zap.NewAtomicLevelAt(getZapLevel(config.FileLevel)),
+	}
+
+	if config.EnableConsole {
+		writer := zapcore.Lock(os.Stderr)
+		core := zapcore.NewCore(makeEncoder(config.ConsoleJSON), writer, logger.consoleLevel)
+		cores = append(cores, core)
+	}
+
+	if config.EnableFile {
+		writer := zapcore.AddSync(&lumberjack.Logger{
+			Filename: config.FileLocation,
+			MaxSize:  100,
+			Compress: true,
+		})
+		core := zapcore.NewCore(makeEncoder(config.FileJSON), writer, logger.fileLevel)
+		cores = append(cores, core)
+	}
+
+	combinedCore := zapcore.NewTee(cores...)
+
+	logger.zap = zap.New(combinedCore,
+		zap.AddCaller(),
+	)
+
+	return logger
+}
+
+func (l *Logger) Debug(message string, fields ...Field) {
+	l.zap.Debug(message, fields...)
+}
+
+func (l *Logger) Info(message string, fields ...Field) {
+	l.zap.Info(message, fields...)
+}
+
+func (l *Logger) Warn(message string, fields ...Field) {
+	l.zap.Warn(message, fields...)
+}
+
+func (l *Logger) Error(message string, fields ...Field) {
+	l.zap.Error(message, fields...)
+}
+
+func getZapLevel(level string) zapcore.Level {
+	switch level {
+	case LevelInfo:
+		return zapcore.InfoLevel
+	case LevelWarn:
+		return zapcore.WarnLevel
+	case LevelDebug:
+		return zapcore.DebugLevel
+	case LevelError:
+		return zapcore.ErrorLevel
+	default:
+		return zapcore.InfoLevel
+	}
+}
+
+func makeEncoder(json bool) zapcore.Encoder {
+	encoderConfig := zap.NewProductionEncoderConfig()
+	if json {
+		return zapcore.NewJSONEncoder(encoderConfig)
+	}
+
+	encoderConfig.EncodeTime = zapcore.ISO8601TimeEncoder
+	return zapcore.NewConsoleEncoder(encoderConfig)
+}