Skip to content

add local windows event log source #785

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 6 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
## X.Y.Z (Unreleased)
* Add new change notes here
* Add support for local windows event log source for installed collectors

## 3.1.1 (July 8, 2025)

Expand Down
1 change: 1 addition & 0 deletions sumologic/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,7 @@ func Provider() *schema.Provider {
"sumologic_source_template": resourceSumologicSourceTemplate(),
"sumologic_azure_metrics_source": resourceSumologicGenericPollingSource(),
"sumologic_scan_budget": resourceSumologicScanBudget(),
"sumologic_local_windows_event_log_source": resourceSumologicLocalWindowsEventLogSource(),
},
DataSourcesMap: map[string]*schema.Resource{
"sumologic_cse_log_mapping_vendor_product": dataSourceCSELogMappingVendorAndProduct(),
Expand Down
157 changes: 157 additions & 0 deletions sumologic/resource_sumologic_local_windows_event_log_source.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
package sumologic

import (
"fmt"
"log"
"strconv"

"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation"
)

func resourceSumologicLocalWindowsEventLogSource() *schema.Resource {
LocalWindowsEventLogSource := resourceSumologicSource()
LocalWindowsEventLogSource.Create = resourceSumologicLocalWindowsEventLogSourceCreate
LocalWindowsEventLogSource.Read = resourceSumologicLocalWindowsEventLogSourceRead
LocalWindowsEventLogSource.Update = resourceSumologicLocalWindowsEventLogSourceUpdate
LocalWindowsEventLogSource.Importer = &schema.ResourceImporter{
State: resourceSumologicSourceImport,
}

// Windows Event Log specific fields
LocalWindowsEventLogSource.Schema["log_names"] = &schema.Schema{
Type: schema.TypeList,
Required: true,
Elem: &schema.Schema{Type: schema.TypeString},
Description: "List of Windows log types to collect (e.g., Security, Application, System)",
}

LocalWindowsEventLogSource.Schema["render_messages"] = &schema.Schema{
Type: schema.TypeBool,
Optional: true,
Default: true,
Description: "When using legacy format, indicates if full event messages are collected",
}

LocalWindowsEventLogSource.Schema["event_format"] = &schema.Schema{
Type: schema.TypeInt,
Optional: true,
Default: 0,
ValidateFunc: validation.IntInSlice([]int{0, 1}),
Description: "0 for legacy format (XML), 1 for JSON format",
}

LocalWindowsEventLogSource.Schema["event_message"] = &schema.Schema{
Type: schema.TypeInt,
Optional: true,
ValidateFunc: validation.IntInSlice([]int{0, 1, 2}),
Description: "0 for complete message, 1 for message title, 2 for metadata only. Required if event_format is 0",
}

LocalWindowsEventLogSource.Schema["deny_list"] = &schema.Schema{
Type: schema.TypeString,
Optional: true,
Description: "Comma-separated list of event IDs to deny",
}

LocalWindowsEventLogSource.Schema["allow_list"] = &schema.Schema{
Type: schema.TypeString,
Optional: true,
Description: "Comma-separated list of event IDs to allow",
}

return LocalWindowsEventLogSource
}

func resourceSumologicLocalWindowsEventLogSourceCreate(d *schema.ResourceData, meta interface{}) error {
c := meta.(*Client)

if d.Id() == "" {
source := resourceToLocalWindowsEventLogSource(d)
collectorID := d.Get("collector_id").(int)

id, err := c.CreateLocalWindowsEventLogSource(source, collectorID)
if err != nil {
return err
}

d.SetId(strconv.Itoa(id))
}

return resourceSumologicLocalWindowsEventLogSourceRead(d, meta)
}

func resourceSumologicLocalWindowsEventLogSourceUpdate(d *schema.ResourceData, meta interface{}) error {
c := meta.(*Client)

source := resourceToLocalWindowsEventLogSource(d)

err := c.UpdateLocalWindowsEventLogSource(source, d.Get("collector_id").(int))

if err != nil {
return err
}

return resourceSumologicLocalWindowsEventLogSourceRead(d, meta)
}

func resourceToLocalWindowsEventLogSource(d *schema.ResourceData) LocalWindowsEventLogSource {

source := resourceToSource(d)
source.Type = "LocalWindowsEventLog"

LocalWindowsEventLogSource := LocalWindowsEventLogSource{
Source: source,
LogNames: d.Get("log_names").([]interface{}),
RenderMessages: d.Get("render_messages").(bool),
EventFormat: d.Get("event_format").(int),
}

// Handle optional deny_list
if DenyList, ok := d.GetOk("deny_list"); ok {
LocalWindowsEventLogSource.DenyList = DenyList.(string)
}

// Handle optional allow_list
if AllowList, ok := d.GetOk("allow_list"); ok {
LocalWindowsEventLogSource.AllowList = AllowList.(string)
}

// Handle optional event_message field
if eventMessage, ok := d.GetOk("event_message"); ok {
eventMessageInt := eventMessage.(int)
LocalWindowsEventLogSource.EventMessage = &eventMessageInt
}

return LocalWindowsEventLogSource

}

func resourceSumologicLocalWindowsEventLogSourceRead(d *schema.ResourceData, meta interface{}) error {
c := meta.(*Client)

id, _ := strconv.Atoi(d.Id())
source, err := c.GetLocalWindowsEventLogSource(d.Get("collector_id").(int), id)

if err != nil {
return err
}

if source == nil {
log.Printf("[WARN] Local Windows Event Log source not found, removing from state: %v - %v", id, err)
d.SetId("")
return nil
}

if err := resourceSumologicSourceRead(d, source.Source); err != nil {
return fmt.Errorf("%s", err)
}
d.Set("log_names", source.LogNames)
d.Set("render_messages", source.RenderMessages)
d.Set("event_format", source.EventFormat)
d.Set("deny_list", source.DenyList)
d.Set("allow_list", source.AllowList)
d.Set("event_message", source.EventMessage)

return nil
}
83 changes: 83 additions & 0 deletions sumologic/sumologic_local_windows_event_log_source.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
package sumologic

import (
"encoding/json"
"fmt"
)

type LocalWindowsEventLogSource struct {
Source
LogNames []interface{} `json:"logNames"`
RenderMessages bool `json:"renderMessages"`
EventFormat int `json:"eventFormat"`
EventMessage *int `json:"eventMessage,omitempty"`
DenyList string `json:"denylist,omitempty"`
AllowList string `json:"allowlist,omitempty"`
}

func (s *Client) CreateLocalWindowsEventLogSource(source LocalWindowsEventLogSource, collectorID int) (int, error) {

type LocalWindowsEventLogSourceMessage struct {
Source LocalWindowsEventLogSource `json:"source"`
}

request := LocalWindowsEventLogSourceMessage{
Source: source,
}

urlPath := fmt.Sprintf("v1/collectors/%d/sources", collectorID)
body, err := s.Post(urlPath, request)

if err != nil {
return -1, err
}

var response LocalWindowsEventLogSourceMessage

err = json.Unmarshal(body, &response)
if err != nil {
return -1, err
}

return response.Source.ID, nil
}

func (s *Client) GetLocalWindowsEventLogSource(collectorID, sourceID int) (*LocalWindowsEventLogSource, error) {
body, err := s.Get(fmt.Sprintf("v1/collectors/%d/sources/%d", collectorID, sourceID))
if err != nil {
return nil, err
}

if body == nil {
return nil, nil
}

type LocalWindowsEventLogSourceResponse struct {
Source LocalWindowsEventLogSource `json:"source"`
}

var response LocalWindowsEventLogSourceResponse
err = json.Unmarshal(body, &response)
if err != nil {
return nil, err
}

return &response.Source, nil

}

func (s *Client) UpdateLocalWindowsEventLogSource(source LocalWindowsEventLogSource, collectorID int) error {

type LocalWindowsEventLogMessage struct {
Source LocalWindowsEventLogSource `json:"source"`
}

request := LocalWindowsEventLogMessage{
Source: source,
}

urlPath := fmt.Sprintf("v1/collectors/%d/sources/%d", collectorID, source.ID)
_, err := s.Put(urlPath, request)

return err
}
83 changes: 83 additions & 0 deletions website/docs/r/local_windows_event_source.html.markdown
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
---
layout: "sumologic"
page_title: "SumoLogic: sumologic_local_windows_event_log_source"
description: |-
Provides a Sumologic Local Windows Event Log Source.
---

# sumologic_local_windows_event_source
Provides a [Sumologic Local Windows Event Log Source][1].

Note: installed collector sources are a special case for terraform based management. It is not possible to install a local collector via the API, only to add sources to it. The installed collector must be done installed locally on the instance and be set to cloud managed mode to allow for API based configuration.

## Example Usage

Example: 1 This will configure JSON format with "concise" setting and pick up System and Application logs with /os/windows/events as the source category.

```hcl
data "sumologic_collector" "installed_collector" {
name = "terraform_source_testing"
}

resource "sumologic_local_windows_event_log_source" "local" {
name = "windows_logs"
description = "windows system and application logs in json format"
category = "/os/windows/events"
collector_id = "${data.sumologic_collector.installed_collector.id}"
log_names = ["System","Application"]
event_format = 1
}
```

Example 2: Using custom logs and a deny list

```hcl
resource "sumologic_local_windows_event_log_source" "local" {
name = "windows_logs"
description = "windows logs in json format"
category = "/os/windows/events"
collector_id = "${data.sumologic_collector.installed_collector.id}"
log_names = ["System","Application","Microsoft-Windows-PowerShell/Operational", "Microsoft-Windows-TaskScheduler/Operational"]
deny_list = "9999,7890"
event_format = 1
}
```

## Argument Reference

The following arguments are supported:

* `name` - (Required) The name of the local file source. This is required, and has to be unique. Changing this will force recreation the source.
* `description` - (Optional) The description of the source.
* `log_names` - List of Windows log types to collect (e.g., Security, Application, System)
* `render_messages` - When using legacy format, indicates if full event messages are collected
* `event_format` - 0 for legacy format (XML), 1 for JSON format. Default 0.
* `event_message` - 0 for complete message, 1 for message title, 2 for metadata only. Required if event_format is 0
* `deny_list` - Comma-separated list of event IDs to deny
* `category` - (Optional) The default source category for the source.
* `fields` - (Optional) Map containing [key/value pairs][2].
* `allow_list` - (Optional) Comma-separated list of event IDs to allow.

### See also

* [Common Source Properties](https://github.com/terraform-providers/terraform-provider-sumologic/tree/master/website#common-source-properties)
* [Windows Event Source properties](https://help.sumologic.com/docs/send-data/use-json-configure-sources/json-parameters-installed-sources/#local-windows-event-logsource)

## Attributes Reference
The following attributes are exported:

* `id` - The internal ID of the local file source.

## Import
Local Windows Event Log Sources can be imported using the collector and source IDs, e.g.:

```hcl
terraform import sumologic_local_windows_event_source.test 123/456
```

```hcl
terraform import sumologic_local_windows_event_source.test my-test-collector/my-test-source
```

[1]: https://help.sumologic.com/docs/send-data/installed-collectors/sources/local-windows-event-log-source/
[2]: https://help.sumologic.com/Manage/Fields
Loading