func (client *Client) Log(level LogLevel, source LogSource, containerID string, args ...interface{}) {
	payload := api.LogEntry{
		Level:       level.String(),
		Source:      source.String(),
		ContainerID: containerID,
		Message:     fmt.Sprint(args...),
	}
	data, _ := json.Marshal(&payload)
	_ = client.sendStream(api.StreamLog, data)
}
Log sends log entries.
package client
import (
	"encoding/json"
	"errors"
	"fmt"
	"net"
	"syscall"
	"github.com/clearcontainers/proxy/api"
)
type Client struct {
	conn net.Conn
}
func NewClient(conn net.Conn) *Client {
	return &Client{
		conn: conn,
	}
}
func (client *Client) Close() {
	client.conn.Close()
}
func (client *Client) sendCommandFull(cmd api.Command, payload interface{},
	waitForResponse bool) (*api.Frame, error) {
	var data []byte
	var frame *api.Frame
	var err error
	if payload != nil {
		if data, err = json.Marshal(payload); err != nil {
			return nil, err
		}
	}
	if err := api.WriteCommand(client.conn, cmd, data); err != nil {
		return nil, err
	}
	if !waitForResponse {
		return nil, nil
	}
	if frame, err = api.ReadFrame(client.conn); err != nil {
		return nil, err
	}
	if cmd == api.CmdSignal {
		payloadSignal, ok := payload.(*api.Signal)
		if !ok {
			return nil, err
		}
		if payloadSignal.SignalNumber == int(syscall.SIGKILL) ||
			payloadSignal.SignalNumber == int(syscall.SIGTERM) {
			if frame.Header.Type != api.TypeNotification {
				return nil, fmt.Errorf("unexpected frame type %v", frame.Header.Type)
			}
			if frame, err = api.ReadFrame(client.conn); err != nil {
				return nil, err
			}
		}
	}
	if frame.Header.Type != api.TypeResponse {
		return nil, fmt.Errorf("unexpected frame type %v", frame.Header.Type)
	}
	if frame.Header.Opcode != int(cmd) {
		return nil, fmt.Errorf("unexpected opcode %v", frame.Header.Opcode)
	}
	return frame, nil
}
func (client *Client) sendCommand(cmd api.Command, payload interface{}) (*api.Frame, error) {
	return client.sendCommandFull(cmd, payload, true)
}
func (client *Client) sendCommandNoResponse(cmd api.Command, payload interface{}) error {
	_, err := client.sendCommandFull(cmd, payload, false)
	return err
}
func errorFromResponse(resp *api.Frame) error {
	if !resp.Header.InError {
		return nil
	}
	decoded := api.ErrorResponse{}
	if err := json.Unmarshal(resp.Payload, &decoded); err != nil {
		return err
	}
	if decoded.Message == "" {
		return errors.New("unknown error")
	}
	return errors.New(decoded.Message)
}
func unmarshalResponse(resp *api.Frame, decoded interface{}) error {
	if len(resp.Payload) == 0 {
		return nil
	}
	return json.Unmarshal(resp.Payload, decoded)
}
type RegisterVMOptions struct {
	Console      string
	NumIOStreams int
}
type RegisterVMReturn api.RegisterVMResponse
func (client *Client) RegisterVM(containerID, ctlSerial, ioSerial string,
	options *RegisterVMOptions) (*RegisterVMReturn, error) {
	payload := api.RegisterVM{
		ContainerID: containerID,
		CtlSerial:   ctlSerial,
		IoSerial:    ioSerial,
	}
	if options != nil {
		payload.Console = options.Console
		payload.NumIOStreams = options.NumIOStreams
	}
	resp, err := client.sendCommand(api.CmdRegisterVM, &payload)
	if err != nil {
		return nil, err
	}
	if err := errorFromResponse(resp); err != nil {
		return nil, err
	}
	decoded := RegisterVMReturn{}
	err = unmarshalResponse(resp, &decoded)
	return &decoded, err
}
type AttachVMOptions struct {
	NumIOStreams int
}
type AttachVMReturn api.AttachVMResponse
func (client *Client) AttachVM(containerID string, options *AttachVMOptions) (*AttachVMReturn, error) {
	payload := api.AttachVM{
		ContainerID: containerID,
	}
	if options != nil {
		payload.NumIOStreams = options.NumIOStreams
	}
	resp, err := client.sendCommand(api.CmdAttachVM, &payload)
	if err != nil {
		return nil, err
	}
	if err := errorFromResponse(resp); err != nil {
		return nil, err
	}
	decoded := AttachVMReturn{}
	err = unmarshalResponse(resp, &decoded)
	return &decoded, err
}
func (client *Client) Hyper(hyperName string, hyperMessage interface{}) ([]byte, error) {
	return client.HyperWithTokens(hyperName, nil, hyperMessage)
}
func (client *Client) HyperWithTokens(hyperName string, tokens []string, hyperMessage interface{}) ([]byte, error) {
	var data []byte
	if hyperMessage != nil {
		var err error
		data, err = json.Marshal(hyperMessage)
		if err != nil {
			return nil, err
		}
	}
	hyper := api.Hyper{
		HyperName: hyperName,
		Data:      data,
	}
	if tokens != nil {
		hyper.Tokens = tokens
	}
	resp, err := client.sendCommand(api.CmdHyper, &hyper)
	if err != nil {
		return nil, err
	}
	if err = errorFromResponse(resp); err != nil {
		return nil, err
	}
	return resp.Payload, errorFromResponse(resp)
}
func (client *Client) UnregisterVM(containerID string) error {
	payload := api.UnregisterVM{
		ContainerID: containerID,
	}
	resp, err := client.sendCommand(api.CmdUnregisterVM, &payload)
	if err != nil {
		return err
	}
	return errorFromResponse(resp)
}
func (client *Client) ConnectShim(token string) error {
	payload := api.ConnectShim{
		Token: token,
	}
	resp, err := client.sendCommand(api.CmdConnectShim, &payload)
	if err != nil {
		return err
	}
	return errorFromResponse(resp)
}
func (client *Client) DisconnectShim() error {
	return client.sendCommandNoResponse(api.CmdDisconnectShim, nil)
}
func (client *Client) signal(signal syscall.Signal, columns, rows int) error {
	payload := api.Signal{
		SignalNumber: int(signal),
		Columns:      columns,
		Rows:         rows,
	}
	resp, err := client.sendCommand(api.CmdSignal, &payload)
	if err != nil {
		return err
	}
	return errorFromResponse(resp)
}
func (client *Client) Kill(signal syscall.Signal) error {
	return client.signal(signal, 0, 0)
}
func (client *Client) SendTerminalSize(columns, rows int) error {
	return client.signal(syscall.SIGWINCH, columns, rows)
}
func (client *Client) sendStream(op api.Stream, data []byte) error {
	return api.WriteStream(client.conn, op, data)
}
func (client *Client) SendStdin(data []byte) error {
	return client.sendStream(api.StreamStdin, data)
}
type LogLevel uint8
const (
	LogLevelDebug LogLevel = iota
	LogLevelInfo
	LogLevelWarn
	LogLevelError
	logLevelMax
)
var levelToString = []string{"debug", "info", "warn", "error"}
func (l LogLevel) String() string {
	if l < logLevelMax {
		return levelToString[l]
	}
	return "unknown"
}
type LogSource uint8
const (
	LogSourceRuntime LogSource = iota
	LogSourceShim
	logSourceMax
)
var sourceToString = []string{"runtime", "shim"}
func (s LogSource) String() string {
	if s < logSourceMax {
		return sourceToString[s]
	}
	return "unknown"
}