205 lines
6.2 KiB
Go
205 lines
6.2 KiB
Go
|
// Licensed to Elasticsearch B.V. under one or more contributor
|
||
|
// license agreements. See the NOTICE file distributed with
|
||
|
// this work for additional information regarding copyright
|
||
|
// ownership. Elasticsearch B.V. licenses this file to you under
|
||
|
// the Apache License, Version 2.0 (the "License"); you may
|
||
|
// not use this file except in compliance with the License.
|
||
|
// You may obtain a copy of the License at
|
||
|
//
|
||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||
|
//
|
||
|
// Unless required by applicable law or agreed to in writing,
|
||
|
// software distributed under the License is distributed on an
|
||
|
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||
|
// KIND, either express or implied. See the License for the
|
||
|
// specific language governing permissions and limitations
|
||
|
// under the License.
|
||
|
|
||
|
package sys
|
||
|
|
||
|
import (
|
||
|
"encoding/xml"
|
||
|
"fmt"
|
||
|
"time"
|
||
|
)
|
||
|
|
||
|
// UnmarshalEventXML unmarshals the given XML into a new Event.
|
||
|
func UnmarshalEventXML(rawXML []byte) (Event, error) {
|
||
|
var event Event
|
||
|
err := xml.Unmarshal(rawXML, &event)
|
||
|
return event, err
|
||
|
}
|
||
|
|
||
|
// Event holds the data from a log record.
|
||
|
type Event struct {
|
||
|
// System
|
||
|
Provider Provider `xml:"System>Provider"`
|
||
|
EventIdentifier EventIdentifier `xml:"System>EventID"`
|
||
|
Version uint8 `xml:"System>Version"`
|
||
|
LevelRaw uint8 `xml:"System>Level"`
|
||
|
TaskRaw uint16 `xml:"System>Task"`
|
||
|
OpcodeRaw uint8 `xml:"System>Opcode"`
|
||
|
TimeCreated TimeCreated `xml:"System>TimeCreated"`
|
||
|
RecordID uint64 `xml:"System>EventRecordID"`
|
||
|
Correlation Correlation `xml:"System>Correlation"`
|
||
|
Execution Execution `xml:"System>Execution"`
|
||
|
Channel string `xml:"System>Channel"`
|
||
|
Computer string `xml:"System>Computer"`
|
||
|
User SID `xml:"System>Security"`
|
||
|
|
||
|
EventData EventData `xml:"EventData"`
|
||
|
UserData UserData `xml:"UserData"`
|
||
|
|
||
|
// RenderingInfo
|
||
|
Message string `xml:"RenderingInfo>Message"`
|
||
|
Level string `xml:"RenderingInfo>Level"`
|
||
|
Task string `xml:"RenderingInfo>Task"`
|
||
|
Opcode string `xml:"RenderingInfo>Opcode"`
|
||
|
Keywords []string `xml:"RenderingInfo>Keywords>Keyword"`
|
||
|
|
||
|
// ProcessingErrorData
|
||
|
RenderErrorCode uint32 `xml:"ProcessingErrorData>ErrorCode"`
|
||
|
RenderErrorDataItemName string `xml:"ProcessingErrorData>DataItemName"`
|
||
|
RenderErr string
|
||
|
}
|
||
|
|
||
|
// Provider identifies the provider that logged the event. The Name and GUID
|
||
|
// attributes are included if the provider used an instrumentation manifest to
|
||
|
// define its events; otherwise, the EventSourceName attribute is included if a
|
||
|
// legacy event provider (using the Event Logging API) logged the event.
|
||
|
type Provider struct {
|
||
|
Name string `xml:"Name,attr"`
|
||
|
GUID string `xml:"Guid,attr"`
|
||
|
EventSourceName string `xml:"EventSourceName,attr"`
|
||
|
}
|
||
|
|
||
|
// Correlation contains activity identifiers that consumers can use to group
|
||
|
// related events together.
|
||
|
type Correlation struct {
|
||
|
ActivityID string `xml:"ActivityID,attr"`
|
||
|
RelatedActivityID string `xml:"RelatedActivityID,attr"`
|
||
|
}
|
||
|
|
||
|
// Execution contains information about the process and thread that logged the
|
||
|
// event.
|
||
|
type Execution struct {
|
||
|
ProcessID uint32 `xml:"ProcessID,attr"`
|
||
|
ThreadID uint32 `xml:"ThreadID,attr"`
|
||
|
|
||
|
// Only available for events logged to an event tracing log file (.etl file).
|
||
|
ProcessorID uint32 `xml:"ProcessorID,attr"`
|
||
|
SessionID uint32 `xml:"SessionID,attr"`
|
||
|
KernelTime uint32 `xml:"KernelTime,attr"`
|
||
|
UserTime uint32 `xml:"UserTime,attr"`
|
||
|
ProcessorTime uint32 `xml:"ProcessorTime,attr"`
|
||
|
}
|
||
|
|
||
|
// EventIdentifier is the identifer that the provider uses to identify a
|
||
|
// specific event type.
|
||
|
type EventIdentifier struct {
|
||
|
Qualifiers uint16 `xml:"Qualifiers,attr"`
|
||
|
ID uint32 `xml:",chardata"`
|
||
|
}
|
||
|
|
||
|
// TimeCreated contains the system time of when the event was logged.
|
||
|
type TimeCreated struct {
|
||
|
SystemTime time.Time
|
||
|
}
|
||
|
|
||
|
// UnmarshalXML unmarshals an XML dataTime string.
|
||
|
func (t *TimeCreated) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
|
||
|
attrs := struct {
|
||
|
SystemTime string `xml:"SystemTime,attr"`
|
||
|
RawTime uint64 `xml:"RawTime,attr"`
|
||
|
}{}
|
||
|
|
||
|
err := d.DecodeElement(&attrs, &start)
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
|
||
|
if attrs.SystemTime != "" {
|
||
|
// This works but XML dateTime is really ISO8601.
|
||
|
t.SystemTime, err = time.Parse(time.RFC3339Nano, attrs.SystemTime)
|
||
|
} else if attrs.RawTime != 0 {
|
||
|
// The units for RawTime are not specified in the documentation. I think
|
||
|
// it is only used in event tracing so this shouldn't be a problem.
|
||
|
err = fmt.Errorf("failed to unmarshal TimeCreated RawTime='%d'", attrs.RawTime)
|
||
|
}
|
||
|
|
||
|
return err
|
||
|
}
|
||
|
|
||
|
// EventData contains the event data. The EventData section is used if the
|
||
|
// message provider template does not contain a UserData section.
|
||
|
type EventData struct {
|
||
|
Pairs []KeyValue `xml:",any"`
|
||
|
}
|
||
|
|
||
|
// UserData contains the event data.
|
||
|
type UserData struct {
|
||
|
Name xml.Name
|
||
|
Pairs []KeyValue
|
||
|
}
|
||
|
|
||
|
// UnmarshalXML unmarshals UserData XML.
|
||
|
func (u *UserData) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
|
||
|
// Assume that UserData has the same general key-value structure as
|
||
|
// EventData does.
|
||
|
in := struct {
|
||
|
Pairs []KeyValue `xml:",any"`
|
||
|
}{}
|
||
|
|
||
|
// Read tokens until we find the first StartElement then unmarshal it.
|
||
|
for {
|
||
|
t, err := d.Token()
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
|
||
|
if se, ok := t.(xml.StartElement); ok {
|
||
|
err = d.DecodeElement(&in, &se)
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
|
||
|
u.Name = se.Name
|
||
|
u.Pairs = in.Pairs
|
||
|
d.Skip()
|
||
|
break
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
// KeyValue is a key value pair of strings.
|
||
|
type KeyValue struct {
|
||
|
Key string
|
||
|
Value string
|
||
|
}
|
||
|
|
||
|
// UnmarshalXML unmarshals an arbitrary XML element into a KeyValue. The key
|
||
|
// becomes the name of the element or value of the Name attribute if it exists.
|
||
|
// The value is the character data contained within the element.
|
||
|
func (kv *KeyValue) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
|
||
|
elem := struct {
|
||
|
XMLName xml.Name
|
||
|
Name string `xml:"Name,attr"`
|
||
|
Value string `xml:",chardata"`
|
||
|
}{}
|
||
|
|
||
|
err := d.DecodeElement(&elem, &start)
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
|
||
|
kv.Key = elem.XMLName.Local
|
||
|
if elem.Name != "" {
|
||
|
kv.Key = elem.Name
|
||
|
}
|
||
|
kv.Value = elem.Value
|
||
|
|
||
|
return nil
|
||
|
}
|