You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@plc4x.apache.org by sr...@apache.org on 2022/07/29 15:25:15 UTC

[plc4x] branch develop updated: feat(plc4go): first implementation of plc4xbrowser

This is an automated email from the ASF dual-hosted git repository.

sruehl pushed a commit to branch develop
in repository https://gitbox.apache.org/repos/asf/plc4x.git


The following commit(s) were added to refs/heads/develop by this push:
     new 027ef30a9 feat(plc4go): first implementation of plc4xbrowser
027ef30a9 is described below

commit 027ef30a90835d04f969dfc3161e440b271f42dd
Author: Sebastian Rühl <sr...@apache.org>
AuthorDate: Fri Jul 29 17:22:22 2022 +0200

    feat(plc4go): first implementation of plc4xbrowser
    
    This is a small terminal ui to communicate to a plc using plc4x
---
 plc4go/go.mod                     |   6 +-
 plc4go/go.sum                     |  16 +-
 plc4go/tools/plc4xbrowser/main.go | 298 ++++++++++++++++++++++++++++++++++++++
 3 files changed, 318 insertions(+), 2 deletions(-)

diff --git a/plc4go/go.mod b/plc4go/go.mod
index 6024c3228..e9399fef8 100644
--- a/plc4go/go.mod
+++ b/plc4go/go.mod
@@ -31,6 +31,7 @@ require (
 	github.com/k0kubun/go-ansi v0.0.0-20180517002512-3bf9e2903213
 	github.com/libp2p/go-reuseport v0.2.0
 	github.com/pkg/errors v0.9.1
+	github.com/rivo/tview v0.0.0-20220728094620-c6cff75ed57b
 	github.com/rs/zerolog v1.27.0
 	github.com/schollz/progressbar/v3 v3.8.7
 	github.com/snksoft/crc v1.1.0
@@ -45,8 +46,11 @@ require (
 	github.com/antchfx/xpath v0.0.0-20170515025933-1f3266e77307 // indirect
 	github.com/davecgh/go-spew v1.1.1 // indirect
 	github.com/fsnotify/fsnotify v1.5.4 // indirect
+	github.com/gdamore/encoding v1.0.0 // indirect
+	github.com/gdamore/tcell/v2 v2.5.1 // indirect
 	github.com/hashicorp/hcl v1.0.0 // indirect
 	github.com/inconshreveable/mousetrap v1.0.0 // indirect
+	github.com/lucasb-eyer/go-colorful v1.2.0 // indirect
 	github.com/magiconair/properties v1.8.6 // indirect
 	github.com/mattn/go-colorable v0.1.12 // indirect
 	github.com/mattn/go-isatty v0.0.14 // indirect
@@ -56,7 +60,7 @@ require (
 	github.com/pelletier/go-toml v1.9.5 // indirect
 	github.com/pelletier/go-toml/v2 v2.0.1 // indirect
 	github.com/pmezard/go-difflib v1.0.0 // indirect
-	github.com/rivo/uniseg v0.2.0 // indirect
+	github.com/rivo/uniseg v0.3.1 // indirect
 	github.com/spf13/afero v1.8.2 // indirect
 	github.com/spf13/cast v1.5.0 // indirect
 	github.com/spf13/jwalterweatherman v1.1.0 // indirect
diff --git a/plc4go/go.sum b/plc4go/go.sum
index b86f32bd2..e0883a5f6 100644
--- a/plc4go/go.sum
+++ b/plc4go/go.sum
@@ -68,6 +68,11 @@ github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYF
 github.com/frankban/quicktest v1.14.3 h1:FJKSZTDHjyhriyC81FLQ0LY93eSai0ZyR/ZIkd3ZUKE=
 github.com/fsnotify/fsnotify v1.5.4 h1:jRbGcIw6P2Meqdwuo0H1p6JVLbL5DHKAKlYndzMwVZI=
 github.com/fsnotify/fsnotify v1.5.4/go.mod h1:OVB6XrOHzAwXMpEM7uPOzcehqUV2UqJxmVXmkdnm1bU=
+github.com/gdamore/encoding v1.0.0 h1:+7OoQ1Bc6eTm5niUzBa0Ctsh6JbMW6Ra+YNuAtDBdko=
+github.com/gdamore/encoding v1.0.0/go.mod h1:alR0ol34c49FCSBLjhosxzcPHQbf2trDkoo5dl+VrEg=
+github.com/gdamore/tcell/v2 v2.4.1-0.20210905002822-f057f0a857a1/go.mod h1:Az6Jt+M5idSED2YPGtwnfJV0kXohgdCBPmHGSYc1r04=
+github.com/gdamore/tcell/v2 v2.5.1 h1:zc3LPdpK184lBW7syF2a5C6MV827KmErk9jGVnmsl/I=
+github.com/gdamore/tcell/v2 v2.5.1/go.mod h1:wSkrPaXoiIWZqW/g7Px4xc79di6FTcpB8tvaKJ6uGBo=
 github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
 github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
 github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
@@ -156,6 +161,8 @@ github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
 github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
 github.com/libp2p/go-reuseport v0.2.0 h1:18PRvIMlpY6ZK85nIAicSBuXXvrYoSw3dsBAR7zc560=
 github.com/libp2p/go-reuseport v0.2.0/go.mod h1:bvVho6eLMm6Bz5hmU0LYN3ixd3nPPvtIlaURZZgOY4k=
+github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY=
+github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0=
 github.com/magiconair/properties v1.8.6 h1:5ibWZ6iY0NctNGWo87LalDlEZ6R41TqbbDamhfG/Qzo=
 github.com/magiconair/properties v1.8.6/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60=
 github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
@@ -180,8 +187,11 @@ github.com/pkg/sftp v1.13.1/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qR
 github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
 github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
 github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
-github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY=
+github.com/rivo/tview v0.0.0-20220728094620-c6cff75ed57b h1:/RX/1JPloj+3P0aYh1N6jfKNWUg1NEIeAHFLc+8UOOU=
+github.com/rivo/tview v0.0.0-20220728094620-c6cff75ed57b/go.mod h1:/Ve2+D+tGMTMNAlGXKCIX9ZeX2InzODYHotmtKZUUVk=
 github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
+github.com/rivo/uniseg v0.3.1 h1:SDPP7SHNl1L7KrEFCSJslJ/DM9DT02Nq2C61XrfHMmk=
+github.com/rivo/uniseg v0.3.1/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
 github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
 github.com/rogpeppe/go-internal v1.6.1 h1:/FiVV8dS/e+YqF2JvO3yXRFbBLTIuSDkuC7aBOAvL+k=
 github.com/rs/xid v1.3.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg=
@@ -361,16 +371,20 @@ golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7w
 golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20210225134936-a50acf3fe073/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210309074719-68d13333faf2/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20220128215802-99c3d69c2c27/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20220318055525-2edf467146b5/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a h1:dGzPydgVsqGcTRVwiLJ1jVbufYwmzD3LfVPLKsKg+0k=
 golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
+golang.org/x/term v0.0.0-20201210144234-2321bbc49cbf/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
+golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
 golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 h1:JGgROgKl9N8DuW20oFS5gxc+lE67/N3FcwmBPMe7ArY=
 golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
 golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
diff --git a/plc4go/tools/plc4xbrowser/main.go b/plc4go/tools/plc4xbrowser/main.go
new file mode 100644
index 000000000..d138cf2ec
--- /dev/null
+++ b/plc4go/tools/plc4xbrowser/main.go
@@ -0,0 +1,298 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF 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
+ *
+ *   https://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 main
+
+import (
+	"fmt"
+	"io"
+	"strconv"
+	"strings"
+	"time"
+
+	"github.com/gdamore/tcell/v2"
+	"github.com/pkg/errors"
+	"github.com/rivo/tview"
+	"github.com/rs/zerolog"
+	"github.com/rs/zerolog/log"
+
+	"github.com/apache/plc4x/plc4go/internal/cbus"
+	plc4go "github.com/apache/plc4x/plc4go/pkg/api"
+	"github.com/apache/plc4x/plc4go/pkg/api/model"
+	"github.com/apache/plc4x/plc4go/pkg/api/transports"
+)
+
+// TODO: replace with real commands
+const plc4xCommands = "connect,disconnect,read,write,register,subscribe"
+
+var connections map[string]plc4go.PlcConnection
+var connectionsChanged func()
+
+var commandsExecuted int
+
+var messagesReceived int
+var messageOutput io.Writer
+
+func init() {
+	connections = make(map[string]plc4go.PlcConnection)
+}
+
+func main() {
+	application := tview.NewApplication()
+
+	newPrimitive := func(text string) tview.Primitive {
+		return tview.NewTextView().
+			SetTextAlign(tview.AlignCenter).
+			SetText(text)
+	}
+	connectionArea := buildConnectionArea(newPrimitive, application)
+	outputArea := buildOutputArea(newPrimitive, application)
+	commandArea := buildCommandArea(newPrimitive, application)
+
+	grid := tview.NewGrid().
+		SetRows(3, 0, 3).
+		SetColumns(30, 0, 30).
+		SetBorders(true).
+		AddItem(newPrimitive("PLC4X Browser"), 0, 0, 1, 3, 0, 0, false).
+		AddItem(newPrimitive("https://github.com/apache/plc4x"), 2, 0, 1, 3, 0, 0, false)
+
+	// Layout for screens narrower than 100 cells (connectionArea and side bar are hidden).
+	grid.AddItem(connectionArea, 0, 0, 0, 0, 0, 0, false).
+		AddItem(outputArea, 1, 0, 1, 3, 0, 0, false).
+		AddItem(commandArea, 0, 0, 0, 0, 0, 0, true)
+
+	// Layout for screens wider than 100 cells.
+	grid.AddItem(connectionArea, 1, 0, 1, 1, 0, 100, false).
+		AddItem(outputArea, 1, 1, 1, 1, 0, 100, false).
+		AddItem(commandArea, 1, 2, 1, 1, 0, 100, false)
+
+	if err := application.SetRoot(grid, true).EnableMouse(true).Run(); err != nil {
+		panic(err)
+	}
+	for _, connection := range connections {
+		connection.Close()
+	}
+}
+
+func buildConnectionArea(newPrimitive func(text string) tview.Primitive, application *tview.Application) tview.Primitive {
+	connectionAreaHeader := newPrimitive("Connections")
+	connectionArea := tview.NewGrid().
+		SetRows(3, 0).
+		SetColumns(0).
+		AddItem(connectionAreaHeader, 0, 0, 1, 1, 0, 0, false)
+	{
+		connectionList := tview.NewList()
+		connectionsChanged = func() {
+			application.QueueUpdateDraw(func() {
+				connectionList.Clear()
+				for connectionString, connection := range connections {
+					connectionList.AddItem(connectionString, "", 0x0, func() {
+						//TODO: disconnect popup
+						_ = connection
+					})
+				}
+			})
+		}
+		connectionArea.AddItem(connectionList, 1, 0, 1, 1, 0, 0, true)
+	}
+	return connectionArea
+}
+
+func buildCommandArea(newPrimitive func(text string) tview.Primitive, application *tview.Application) tview.Primitive {
+	commandAreaHeader := newPrimitive("Commands")
+	commandArea := tview.NewGrid().
+		SetRows(3, 0, 3).
+		SetColumns(0).
+		AddItem(commandAreaHeader, 0, 0, 1, 1, 0, 0, false)
+	{
+		enteredCommands := tview.NewTextView().
+			SetDynamicColors(true).
+			SetRegions(true).
+			SetWordWrap(true).
+			SetChangedFunc(func() {
+				application.Draw()
+			})
+		commandArea.AddItem(enteredCommands, 1, 0, 1, 1, 0, 0, false)
+
+		words := strings.Split(plc4xCommands, ",")
+		commandInputField := tview.NewInputField().
+			SetLabel("PLC4X Command").
+			SetFieldWidth(30)
+		commandInputField.
+			SetDoneFunc(func(key tcell.Key) {
+				commandText := commandInputField.GetText()
+				commandsExecuted++
+				_, _ = fmt.Fprintf(enteredCommands, "%s [\"%d\"]%s[\"\"]\n", time.Now().Format("04:05"), commandsExecuted, commandText)
+				go func() {
+					if err := handleCommand(commandText); err != nil {
+						_, _ = fmt.Fprintf(enteredCommands, "[#ff0000]%s %s[white]\n", time.Now().Format("04:05"), err)
+						return
+					}
+					application.QueueUpdateDraw(func() {
+						commandInputField.SetText("")
+					})
+				}()
+			})
+		commandInputField.SetAutocompleteFunc(func(currentText string) (entries []string) {
+			if len(currentText) == 0 {
+				return
+			}
+			for _, word := range words {
+				if strings.HasPrefix(strings.ToLower(word), strings.ToLower(currentText)) {
+					entries = append(entries, word)
+				}
+			}
+			switch {
+			case strings.HasPrefix(currentText, "subscribe"):
+				for connectionsString, _ := range connections {
+					entries = append(entries, "subscribe "+connectionsString)
+				}
+			}
+			if len(entries) <= 1 {
+				entries = nil
+			}
+			return
+		})
+		commandArea.AddItem(commandInputField, 2, 0, 1, 1, 0, 0, true)
+	}
+	return commandArea
+}
+
+func handleCommand(commandText string) error {
+	switch {
+	case strings.HasPrefix(commandText, "register "):
+	case strings.HasPrefix(commandText, "connect "):
+		host := strings.TrimPrefix(commandText, "connect ")
+		if _, ok := connections[host]; ok {
+			return errors.Errorf("%s already connected", host)
+		}
+		//TODO: we hardcode that to cbus for now
+		connectionString := fmt.Sprintf("c-bus://%s?srchk=true", host)
+		driverManager := plc4go.NewPlcDriverManager()
+		driverManager.RegisterDriver(cbus.NewDriver())
+		transports.RegisterTcpTransport(driverManager)
+		connectionResult := <-driverManager.GetConnection(connectionString)
+		if err := connectionResult.GetErr(); err != nil {
+			return errors.Wrapf(err, "%s can't connect to", host)
+		}
+		log.Info().Msgf("%s connected", host)
+		connections[host] = connectionResult.GetConnection()
+		connectionsChanged()
+	case strings.HasPrefix(commandText, "disconnect "):
+		host := strings.TrimPrefix(commandText, "disconnect ")
+		if connection, ok := connections[host]; !ok {
+			return errors.Errorf("%s not connected", host)
+		} else {
+			closeResult := <-connection.Close()
+			log.Info().Msgf("%s disconnected", host)
+			delete(connections, host)
+			connectionsChanged()
+			if err := closeResult.GetErr(); err != nil {
+				return errors.Wrapf(err, "%s can't close", host)
+			}
+		}
+	case strings.HasPrefix(commandText, "subscribe "):
+		host := strings.TrimPrefix(commandText, "subscribe ")
+		if connection, ok := connections[host]; !ok {
+			return errors.Errorf("%s not connected", host)
+		} else {
+			subscriptionRequest, err := connection.SubscriptionRequestBuilder().
+				AddEventQuery("something", "monitor/*/*").
+				AddItemHandler(func(event model.PlcSubscriptionEvent) {
+					messagesReceived++
+					_, _ = fmt.Fprintf(messageOutput, "[\"%d\"]\n%s[\"\"]", messagesReceived, event)
+				}).
+				Build()
+			if err != nil {
+				return errors.Wrapf(err, "%s can't subscribe", host)
+			}
+			subscriptionRequestResult := <-subscriptionRequest.Execute()
+			if err := subscriptionRequestResult.GetErr(); err != nil {
+				return errors.Wrapf(err, "%s can't subscribe", host)
+			}
+			log.Info().Msgf("subscription result %s", subscriptionRequestResult.GetResponse())
+		}
+	default:
+		return errors.Errorf("%s not found", commandText)
+	}
+	return nil
+}
+
+func buildOutputArea(newPrimitive func(text string) tview.Primitive, application *tview.Application) *tview.Grid {
+	outputAreaHeader := newPrimitive("Output")
+	outputArea := tview.NewGrid().
+		SetRows(3, 0, 10).
+		SetColumns(0).
+		AddItem(outputAreaHeader, 0, 0, 1, 1, 0, 0, false)
+	{
+		{
+			outputView := tview.NewTextView().
+				SetDynamicColors(true).
+				SetRegions(true).
+				SetWordWrap(true).
+				SetChangedFunc(func() {
+					application.Draw()
+				})
+			messageOutput = outputView
+
+			outputView.SetDoneFunc(func(key tcell.Key) {
+				currentSelection := outputView.GetHighlights()
+				if key == tcell.KeyEnter {
+					if len(currentSelection) > 0 {
+						outputView.Highlight()
+					} else {
+						outputView.Highlight("0").ScrollToHighlight()
+					}
+				} else if len(currentSelection) > 0 {
+					index, _ := strconv.Atoi(currentSelection[0])
+					if key == tcell.KeyTab {
+						index = (index + 1) % messagesReceived
+					} else if key == tcell.KeyBacktab {
+						index = (index - 1 + messagesReceived) % messagesReceived
+					} else {
+						return
+					}
+					outputView.Highlight(strconv.Itoa(index)).ScrollToHighlight()
+				}
+			})
+			outputView.SetBorder(false)
+			outputArea.AddItem(outputView, 1, 0, 1, 1, 0, 0, false)
+		}
+
+		{
+			consoleView := tview.NewTextView().
+				SetDynamicColors(true).
+				SetRegions(true).
+				SetWordWrap(true).
+				SetChangedFunc(func() {
+					application.Draw()
+				})
+
+			log.Logger = log.
+				//// Enable below if you want to see the filenames
+				//With().Caller().Logger().
+				Output(zerolog.ConsoleWriter{Out: tview.ANSIWriter(consoleView)}).
+				Level(zerolog.InfoLevel)
+
+			consoleView.SetBorder(false)
+			outputArea.AddItem(consoleView, 2, 0, 1, 1, 0, 0, false)
+		}
+	}
+	return outputArea
+}