Skip to content

Commit 8b67bb1

Browse files
feat(logging): add file logging feature with UI toggle
- Introduced a new setting for enabling file logging in the global settings. - Implemented a live view for displaying logs and a UI toggle for file logging. - Updated router and layout to include the new logs page. - Added migration for the new logging setting.
1 parent 7a18481 commit 8b67bb1

10 files changed

Lines changed: 131 additions & 4 deletions

File tree

assets/css/app.scss

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -306,3 +306,13 @@ main.full-height {
306306
background-color: initial;
307307
}
308308
}
309+
310+
.logs {
311+
background-color: #f5f5f5;
312+
border: 1px solid #ccc;
313+
padding: 10px;
314+
white-space: pre-wrap;
315+
word-wrap: break-word;
316+
height: 500px;
317+
overflow-y: scroll;
318+
}

config/config.exs

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,20 @@ config :teslamate,
1616
TeslaMate.Auth.Tokens
1717
]
1818

19-
config :logger, :console,
20-
format: "$time $metadata[$level] $message\n",
21-
metadata: [:car_id]
19+
config :logger,
20+
backends: [
21+
:console
22+
] ++ (if System.get_env("TESLAMATE_FILE_LOGGING_ENABLED") == "true", do: [{Logger.Handlers.File, :file_logger_for_webview}], else: []),
23+
console: [
24+
format: "$time $metadata[$level] $message\n",
25+
metadata: [:car_id]
26+
],
27+
file_logger_for_webview: [
28+
format: "$time $metadata[$level] $message\n",
29+
metadata: [:car_id],
30+
path: System.get_env("TESLAMATE_FILE_LOGGING_PATH") || Path.join(System.cwd(), "data/logs/teslamate.log"),
31+
sync_threshold: 5 # sync every 5 messages to file
32+
]
2233

2334
config :phoenix, :json_library, Jason
2435

lib/teslamate/settings/global_settings.ex

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ defmodule TeslaMate.Settings.GlobalSettings do
1313
field :grafana_url, :string
1414

1515
field :language, :string
16+
field :file_logging_enabled, :boolean, default: false
1617

1718
timestamps()
1819
end
@@ -91,7 +92,8 @@ defmodule TeslaMate.Settings.GlobalSettings do
9192
:preferred_range,
9293
:base_url,
9394
:grafana_url,
94-
:language
95+
:language,
96+
:file_logging_enabled
9597
])
9698
|> validate_required([
9799
:unit_of_length,
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
defmodule TeslaMateWeb.LogLive.Index do
2+
use TeslaMateWeb, :live_view
3+
4+
@log_file_path System.get_env("TESLAMATE_FILE_LOGGING_PATH") || Path.join(System.cwd(), "data/logs/teslamate.log")
5+
6+
@impl true
7+
def mount(_params, _session, socket) do
8+
{:ok, assign(socket, logs: get_logs())}
9+
end
10+
11+
@impl true
12+
def handle_event("refresh_logs", _params, socket) do
13+
{:noreply, assign(socket, logs: get_logs())}
14+
end
15+
16+
defp get_logs() do
17+
case File.read(@log_file_path) do
18+
{:ok, content} ->
19+
content
20+
|> String.split(~r/\R/, trim: true)
21+
|> Enum.reverse()
22+
23+
{:error, :enoent} ->
24+
["Log file not found. It will be created when logs are written."]
25+
26+
{:error, reason} ->
27+
["Error reading log file: #{reason}"]
28+
end
29+
end
30+
end

lib/teslamate_web/live/settings_live/index.ex

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,9 +80,33 @@ defmodule TeslaMateWeb.SettingsLive.Index do
8080
assign(socket, settings.())
8181
end
8282

83+
if Map.has_key?(params, "file_logging_enabled") do
84+
enabled = params["file_logging_enabled"]
85+
toggle_file_logger(enabled)
86+
end
87+
8388
{:noreply, socket}
8489
end
8590

91+
defp toggle_file_logger(true) do
92+
unless System.get_env("TESLAMATE_FILE_LOGGING_ENABLED") == "true" do
93+
Logger.add_handler(:file_logger_webview, Logger.Handlers.File,
94+
format: "$time $metadata[$level] $message\n",
95+
metadata: [:car_id],
96+
path: "priv/logs/teslamate.log",
97+
sync_threshold: 5 # sync every 5 messages to file
98+
)
99+
Logger.info("File logging enabled via UI.")
100+
end
101+
end
102+
103+
defp toggle_file_logger(false) do
104+
if System.get_env("TESLAMATE_FILE_LOGGING_ENABLED") != "true" do
105+
Logger.remove_handler(:file_logger_webview)
106+
Logger.info("File logging disabled via UI.")
107+
end
108+
end
109+
86110
def handle_event("change", params, %{assigns: %{car_settings: settings, car: id}} = socket) do
87111
params = params["car_settings_#{id}"]
88112

lib/teslamate_web/live/settings_live/index.html.heex

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -339,6 +339,31 @@
339339
</div>
340340
</div>
341341
</div>
342+
343+
<div class="columns is-mobile is-centered">
344+
<div class="column">
345+
<h2 class="title is-4"><%= gettext("Logging") %></h2>
346+
<%= if System.get_env("TESLAMATE_FILE_LOGGING_ENABLED") == "true" do %>
347+
<div class="field is-horizontal center-vertically">
348+
<div class="field-label is-normal is-paddingless">
349+
<%= label(f, :file_logging_enabled, gettext("File Logging"), class: "label") %>
350+
</div>
351+
<div class="field-body">
352+
<div class="field">
353+
<div class="control">
354+
<%= checkbox(f, :file_logging_enabled, class: "switch is-rounded is-success") %>
355+
<%= label(f, :file_logging_enabled, nil) %>
356+
</div>
357+
</div>
358+
</div>
359+
</div>
360+
<% else %>
361+
<p class="help">
362+
<%= gettext("File logging can be enabled by setting the TESLAMATE_FILE_LOGGING_ENABLED environment variable to 'true'.") %>
363+
</p>
364+
<% end %>
365+
</div>
366+
</div>
342367
</.form>
343368

344369
<div class="columns is-mobile is-centered">

lib/teslamate_web/router.ex

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ defmodule TeslaMateWeb.Router do
4444
live "/geo-fences/:id/edit", GeoFenceLive.Form
4545
live "/charge-cost/:id", ChargeLive.Cost
4646
live "/import", ImportLive.Index
47+
live "/logs", LogLive.Index
4748
end
4849
end
4950

lib/teslamate_web/templates/layout/root.html.heex

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,12 @@
100100
>
101101
<span class="icon"><i class="mdi mdi-map-marker-radius"></i></span>&nbsp;<span><%= gettext("Geo-Fences") %></span>
102102
</.link>
103+
<.link
104+
navigate={Routes.live_path(@conn, TeslaMateWeb.LogLive.Index)}
105+
class="navbar-item mr-5"
106+
>
107+
<span class="icon"><i class="mdi mdi-math-log"></i></span>&nbsp;<span><%= gettext("Logs") %></span>
108+
</.link>
103109
<.link
104110
navigate={Routes.live_path(@conn, TeslaMateWeb.SettingsLive.Index)}
105111
class="navbar-item mr-5"
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
<h1>Logs</h1>
2+
3+
<button phx-click="refresh_logs" class="button is-primary">Refresh</button>
4+
5+
<pre class="logs">
6+
<%= for log <- @logs do %>
7+
<%= log %>
8+
<% end %>
9+
</pre>
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
defmodule TeslaMate.Repo.Migrations.AddWebviewLoggingEnabledToGlobalSettings do
2+
use Ecto.Migration
3+
4+
def change do
5+
alter table(:settings) do
6+
add :webview_logging_enabled, :boolean, default: false, null: false
7+
end
8+
end
9+
end

0 commit comments

Comments
 (0)