| package views |
| |
| import ( |
| encJson "encoding/json" |
| "fmt" |
| |
| "github.com/hashicorp/go-hclog" |
| "github.com/hashicorp/terraform/internal/command/views/json" |
| "github.com/hashicorp/terraform/internal/tfdiags" |
| tfversion "github.com/hashicorp/terraform/version" |
| ) |
| |
| // This version describes the schema of JSON UI messages. This version must be |
| // updated after making any changes to this view, the jsonHook, or any of the |
| // command/views/json package. |
| const JSON_UI_VERSION = "1.1" |
| |
| func NewJSONView(view *View) *JSONView { |
| log := hclog.New(&hclog.LoggerOptions{ |
| Name: "terraform.ui", |
| Output: view.streams.Stdout.File, |
| JSONFormat: true, |
| }) |
| jv := &JSONView{ |
| log: log, |
| view: view, |
| } |
| jv.Version() |
| return jv |
| } |
| |
| type JSONView struct { |
| // hclog is used for all output in JSON UI mode. The logger has an internal |
| // mutex to ensure that messages are not interleaved. |
| log hclog.Logger |
| |
| // We hold a reference to the view entirely to allow us to access the |
| // ConfigSources function pointer, in order to render source snippets into |
| // diagnostics. This is even more unfortunate than the same reference in the |
| // view. |
| // |
| // Do not be tempted to dereference the configSource value upon logger init, |
| // as it will likely be updated later. |
| view *View |
| } |
| |
| func (v *JSONView) Version() { |
| version := tfversion.String() |
| v.log.Info( |
| fmt.Sprintf("Terraform %s", version), |
| "type", json.MessageVersion, |
| "terraform", version, |
| "ui", JSON_UI_VERSION, |
| ) |
| } |
| |
| func (v *JSONView) Log(message string) { |
| v.log.Info(message, "type", json.MessageLog) |
| } |
| |
| func (v *JSONView) StateDump(state string) { |
| v.log.Info( |
| "Emergency state dump", |
| "type", json.MessageLog, |
| "state", encJson.RawMessage(state), |
| ) |
| } |
| |
| func (v *JSONView) Diagnostics(diags tfdiags.Diagnostics) { |
| sources := v.view.configSources() |
| for _, diag := range diags { |
| diagnostic := json.NewDiagnostic(diag, sources) |
| switch diag.Severity() { |
| case tfdiags.Warning: |
| v.log.Warn( |
| fmt.Sprintf("Warning: %s", diag.Description().Summary), |
| "type", json.MessageDiagnostic, |
| "diagnostic", diagnostic, |
| ) |
| default: |
| v.log.Error( |
| fmt.Sprintf("Error: %s", diag.Description().Summary), |
| "type", json.MessageDiagnostic, |
| "diagnostic", diagnostic, |
| ) |
| } |
| } |
| } |
| |
| func (v *JSONView) PlannedChange(c *json.ResourceInstanceChange) { |
| v.log.Info( |
| c.String(), |
| "type", json.MessagePlannedChange, |
| "change", c, |
| ) |
| } |
| |
| func (v *JSONView) ResourceDrift(c *json.ResourceInstanceChange) { |
| v.log.Info( |
| fmt.Sprintf("%s: Drift detected (%s)", c.Resource.Addr, c.Action), |
| "type", json.MessageResourceDrift, |
| "change", c, |
| ) |
| } |
| |
| func (v *JSONView) ChangeSummary(cs *json.ChangeSummary) { |
| v.log.Info( |
| cs.String(), |
| "type", json.MessageChangeSummary, |
| "changes", cs, |
| ) |
| } |
| |
| func (v *JSONView) Hook(h json.Hook) { |
| v.log.Info( |
| h.String(), |
| "type", h.HookType(), |
| "hook", h, |
| ) |
| } |
| |
| func (v *JSONView) Outputs(outputs json.Outputs) { |
| v.log.Info( |
| outputs.String(), |
| "type", json.MessageOutputs, |
| "outputs", outputs, |
| ) |
| } |