github.com/kyleu/dbaudit@v0.0.2-0.20240321155047-ff2f2c940496/app/parse/event.go (about)

     1  package parse
     2  
     3  import (
     4  	"strings"
     5  	"time"
     6  
     7  	mssql "github.com/denisenkom/go-mssqldb"
     8  	"github.com/google/uuid"
     9  
    10  	"github.com/kyleu/dbaudit/app/statement"
    11  	"github.com/kyleu/dbaudit/app/util"
    12  )
    13  
    14  type Event struct {
    15  	EventTime      time.Time              `db:"event_time,omitempty" json:"eventTime,omitempty"`
    16  	SessionID      int                    `db:"session_id,omitempty" json:"sessionID,omitempty"`
    17  	ActionID       string                 `db:"action_id,omitempty" json:"actionID,omitempty"`
    18  	SequenceGroup  mssql.UniqueIdentifier `db:"sequence_group_id" json:"sequenceGroup,omitempty"`
    19  	SequenceNumber int                    `db:"sequence_number,omitempty" json:"sequenceNumber,omitempty"`
    20  	Succeeded      bool                   `db:"succeeded,omitempty" json:"succeeded,omitempty"`
    21  	ObjectID       int                    `db:"object_id,omitempty" json:"objectID,omitempty"`
    22  	ClassType      string                 `db:"class_type,omitempty" json:"classType,omitempty"`
    23  	PrincipalName  string                 `db:"session_server_principal_name,omitempty" json:"principalName,omitempty"`
    24  	DatabaseName   string                 `db:"database_name,omitempty" json:"databaseName,omitempty"`
    25  	ObjectName     string                 `db:"object_name,omitempty" json:"objectName,omitempty"`
    26  	Statement      string                 `db:"statement,omitempty" json:"statement,omitempty"`
    27  	AdditionalInfo string                 `db:"additional_information,omitempty" json:"additionalInfo,omitempty"`
    28  	Filename       string                 `db:"file_name,omitempty" json:"filename,omitempty"`
    29  	Offset         int                    `db:"audit_file_offset,omitempty" json:"offset,omitempty"`
    30  	TransactionID  int                    `db:"transaction_id,omitempty" json:"transactionID,omitempty"`
    31  	ClientIP       string                 `db:"client_ip,omitempty" json:"clientIP,omitempty"`
    32  	Application    string                 `db:"application_name,omitempty" json:"application,omitempty"`
    33  	DurationMS     int                    `db:"duration_milliseconds,omitempty" json:"durationMS,omitempty"`
    34  	ResponseRows   int                    `db:"response_rows,omitempty" json:"responseRows,omitempty"`
    35  	AffectedRows   int                    `db:"affected_rows,omitempty" json:"affectedRows,omitempty"`
    36  	ConnectionID   mssql.UniqueIdentifier `db:"connection_id,omitempty" json:"connectionID,omitempty"`
    37  	HostName       string                 `db:"host_name,omitempty" json:"hostName,omitempty"`
    38  }
    39  
    40  func (e *Event) ID() uuid.UUID {
    41  	return util.UUIDFromStringOK(e.SequenceGroup.String())
    42  }
    43  
    44  func (e *Event) Type() string {
    45  	if e.Statement == "select 1;" {
    46  		return "healthcheck"
    47  	}
    48  	switch strings.ToLower(strings.TrimSpace(e.ActionID)) {
    49  	case "bst":
    50  		return "batch_start"
    51  	case "bcm":
    52  		return "batch_complete"
    53  	case "rst":
    54  		return "proc_start"
    55  	case "rcm":
    56  		return "proc_complete"
    57  	case "trbs":
    58  		return "tx_begin_start"
    59  	case "trbc":
    60  		return "tx_begin_complete"
    61  	case "trcs":
    62  		return "tx_commit_start"
    63  	case "trcc":
    64  		return "tx_commit_complete"
    65  	default:
    66  		return "unknown:" + e.ActionID
    67  	}
    68  }
    69  
    70  func (e *Event) Append(x *Event) {
    71  	e.Statement += x.Statement
    72  }
    73  
    74  func (e *Event) Parsed() (string, util.ValueMap, util.ValueMap, error) {
    75  	return parseSQL(e.Statement)
    76  }
    77  
    78  func (e *Event) ToStatement() *statement.Statement {
    79  	t := statement.AllActions.Get(e.Type(), nil)
    80  	conn := util.UUIDFromStringOK(e.ConnectionID.String())
    81  	sql, typs, vals, err := e.Parsed()
    82  	if err != nil {
    83  		vals = util.ValueMap{"parse_error": err.Error()}
    84  	}
    85  	return &statement.Statement{
    86  		ID: e.ID(), SessionID: e.SessionID, Action: t, Succeeded: e.Succeeded, Principal: e.PrincipalName,
    87  		Database: e.DatabaseName, Filename: e.Filename, Host: e.HostName, TransactionID: e.TransactionID,
    88  		ClientIP: e.ClientIP, Duration: e.DurationMS, ConnectionID: conn, RowsAffected: e.AffectedRows,
    89  		RowsReturned: e.ResponseRows, SQL: sql, Types: typs, Values: vals, Occurred: e.EventTime,
    90  	}
    91  }
    92  
    93  type Events []*Event
    94  
    95  func (e Events) Collapse() Events {
    96  	ret := make(Events, 0, len(e))
    97  	for _, x := range e {
    98  		if x.SequenceNumber == 1 {
    99  			ret = append(ret, x)
   100  		} else {
   101  			ret[len(ret)-1].Append(x)
   102  		}
   103  	}
   104  	return ret
   105  }
   106  
   107  func (e Events) ToStatements() statement.Statements {
   108  	ret := make(statement.Statements, 0, len(e))
   109  	for _, x := range e {
   110  		curr := x.ToStatement()
   111  		switch x.Type() {
   112  		default:
   113  			ret = append(ret, curr)
   114  		}
   115  	}
   116  	return ret
   117  }