Erlang OTP 21 How to disable logger console output - erlang

According to erlang documentation is is possibe to configure logger for file only:
from Erlang Documentation:
Modify the default handler to print to a file instead of standard_io:
[{kernel,
[{logger,
[{handler, default, logger_std_h, % {handler, HandlerId, Module,Config}
#{config => #{file => "log/erlang.log"}}}
]}]}].
My config file looks like:
[{kernel,[
{logger_level, error},
{logger,
[{handler, default, logger_std_h,
#{config => #{file => "log/erlang.log"}}}
]
}
]}].
i.o. exactly as in the documentation.
with log level set to error
When I stat application using reabar3 shell following printed into console:
===> The rebar3 shell is a development tool; to deploy applications in production, consider using releases (http://www.rebar3.org/docs/releases)
2019-04-10T15:14:33.363287+02:00 info: application: syntax_tools, started_at: 'node#x201'
2019-04-10T15:14:33.371897+02:00 info: application: compiler, started_at: 'node#x201'
2019-04-10T15:14:33.379962+02:00 info: supervisor: {local,gr_sup}, started: [{pid,<0.1181.0>},{id,gr_counter_sup},{mfargs,{gr_counter_sup,start_link,[]}},{restart_type,permanent},{shutdown,5000},{child_type,supervisor}]
2019-04-10T15:14:33.382379+02:00 info: supervisor: {local,gr_sup}, started: [{pid,<0.1182.0>},{id,gr_param_sup},{mfargs,{gr_param_sup,start_link,[]}},{restart_type,permanent},{shutdown,5000},{child_type,supervisor}]
So, OTP progress messages are not redirected to the file, but still printed to the console and file erlang.log is empty.
How to disable console output and redirect all messages to the file?
P.S. Erlang version:
Erlang/OTP 21 [erts-10.3.2] [source] [64-bit] [smp:4:4] [ds:4:4:10] [async-threads:1] [hipe]

After fighting for a while I found a problem:
In case of a wrong parameter, Logger just do not create file.
Looks like documentation is incomplete
[{kernel,
[{logger,
[{handler, default, logger_std_h, % {handler, HandlerId, Module,Config}
#{config => #{file => "log/erlang.log"}}}
]}]}].
{config => #{file => "log/erlang.log"}}
should be changed to:
#{config => #{ type => {file => "log/erlang.log"}}}}
[{kernel,
[{logger,
[{handler, default, logger_std_h, % {handler, HandlerId, Module,Config}
#{config => #{ type => {file => "log/erlang.log"}}}}
]}]}].
Here: Complete example of logger configuration file

like this:
{logger, [
{handler,default,undefined}
]}

Related

Erlang logger config does not respond to log level setting info

After starting the Erlang shell with erl I create a logger like so
4> Config = #{config => #{file => "./info.log"}, level => info}.
#{config => #{file => "./info.log"},level => info}
5> logger:add_handler(myhandler, logger_std_h, Config).
ok
Then if I try to log a warning message by logger:warn("foo"). it shows up in the log file. But if I try an info message by logger:info("foo"). it does not. Even though the log level has explicitly been set to info in the Config.
erl needs to be started with a kernel parameter to do this.
Starting it with erl -kernel logger_level info works as expected.

Error Compiling Phoenix in production

I am getting an error trying to deploy my app in production, the compile step is failing for some reason with the following
== Compilation error in file lib/my_app_web/endpoint.ex ==
** (UndefinedFunctionError) function
Phoenix.Endpoint.Supervisor.config/2 is undefined (module
Phoenix.Endpoint.Supervisor is not available)
Phoenix.Endpoint.Supervisor.config(:my_app,
MyAppWeb.Endpoint)
lib/my_app_web/endpoint.ex:2: (module)
(stdlib) erl_eval.erl:670: :erl_eval.do_apply/6
I can build it locally (macOS) but not on the server (ubuntu)
macOS
➜ elixir -v
Erlang/OTP 20 [erts-9.3] [source] [64-bit] [smp:4:4] [ds:4:4:10] [async-threads:10] [hipe] [kernel-poll:false] [dtrace]
Elixir 1.6.4 (compiled with OTP 20)
ubuntu
elixir -v
Erlang/OTP 20 [erts-9.1] [source] [64-bit] [smp:2:2] [ds:2:2:10] [async-threads:10] [hipe] [kernel-poll:false]
Elixir 1.6.5 (compiled with OTP 19)
I only notice the minor patch of elixir and OTP at 19 instead of 20, but since its compiling on the server, i don't see how that would matter
Here is the file in question
defmodule MyAppWeb.Endpoint do
use Phoenix.Endpoint, otp_app: :grounded_warrior
socket "/socket", MyAppWeb.UserSocket
# Serve at "/" the static files from "priv/static" directory.
#
# You should set gzip to true if you are running phoenix.digest
# when deploying your static files in production.
plug Plug.Static,
at: "/", from: :grounded_warrior, gzip: false,
only: ~w(dist css fonts images videos js favicon.ico robots.txt)
plug Plug.Static,
at: "/uploads", from: Path.expand('./uploads'), gzip: false
# Code reloading can be explicitly enabled under the
# :code_reloader configuration of your endpoint.
if code_reloading? do
socket "/phoenix/live_reload/socket", Phoenix.LiveReloader.Socket
plug Phoenix.LiveReloader
plug Phoenix.CodeReloader
end
use Appsignal.Phoenix
plug Plug.RequestId
plug Plug.Logger
plug Plug.Parsers,
parsers: [:urlencoded, :multipart, :"Elixir.MyApp.Plug.Parsers.JSON"],
copy_on_header: "stripe-signature",
pass: ["*/*"],
json_decoder: Poison
plug Plug.MethodOverride
plug Plug.Head
# The session will be stored in the cookie and signed,
# this means its contents can be read but not tampered with.
# Set :encryption_salt if you would also like to encrypt it.
plug Plug.Session,
store: :cookie,
key: "_my_app_key",
signing_salt: "*****"
plug Corsica, origins: "*", allow_headers: ["accept", "content-type", "authorization"]
plug MyAppWeb.Router
#doc """
Callback invoked for dynamically configuring the endpoint.
It receives the endpoint configuration and checks if
configuration should be loaded from the system environment.
"""
def init(_key, config) do
if config[:load_from_system_env] do
port = System.get_env("PORT") || raise "expected the PORT environment variable to be set"
{:ok, Keyword.put(config, :http, [:inet6, port: port])}
else
{:ok, config}
end
end
end

Error during starting the application with cowboy example ('noproc', ranch_listener_sup)

I'm trying run this cowboy example using rebar3:
cowboy version 2.0.0-pre.5
What I do is:
rebar3 new app hello_world
copy the example src into my src
updating rebar.config {cowboy,".*", {git, "https://github.com/ninenines/cowboy", {branch, "master"}}}
rebar3 compile. Everything go fine
erl -pa _build/default/lib/*/ebin
application:start(hello_world).
then error occurs
{error,{bad_return,{{hello_world_app,start,[normal,[]]},
{'EXIT',{noproc,{gen_server,call,
[ranch_sup,
{start_child,{{ranch_listener_sup,http},
{ranch_listener_sup,start_link,
[http,100,ranch_tcp,
[{connection_type,supervisor},{port,...}],
cowboy_clear,
#{connection_type => supervisor,...}]},
permanent,infinity,supervisor,
[ranch_listener_sup]}},
infinity]}}}}}}
=INFO REPORT==== 24-Jan-2017::18:34:52 ===
application: hello_world
exited: {bad_return,
{{hello_world_app,start,[normal,[]]},
{'EXIT',
{noproc,
{gen_server,call,
[ranch_sup,
{start_child,
{{ranch_listener_sup,http},
{ranch_listener_sup,start_link,
[http,100,ranch_tcp,
[{connection_type,supervisor},
{port,8080}],
cowboy_clear,
#{connection_type => supervisor,
env => #{dispatch => [{'_',[],
[{[],[],toppage_handler,
[]}]}]}}]},
permanent,infinity,supervisor,
[ranch_listener_sup]}},
infinity]}}}}}
type: temporary
It seems that runch_sup can't start.
What's wrong with my approach?
I want to run exactly the same src code as in example.
Ranch 1.3 depends on the ssl application by default. If you don't
start it, Ranch fails to start. I would recommend matching on ok when
doing ok = application:start(App), you'd have known the issue much
quicker.
by essen
here is the issue

How to configure httpc profiles with rebar3?

How can I set configuration options for httpc's profiles when using rebar3?
Here is the only example being via erl -config inets.config that looks like this:
[{inets,
[{services,[{httpc,[{profile, server1}]},
{httpc, [{profile, server2}]}]}]
}].
I tried adopting it to my rebar3 project structure.
Code
Project was created with rebar3, with standard OTP layout:
rebar3 new release myapp
Here is my myapp/config/sys.config:
[
{ myapp, []},
{inets, [{services, [{httpc, [{profile, myapp}]}]}]}
].
rebar.config:
{erl_opts, [debug_info]}.
{deps, []}.
{relx, [{release, { myapp, "0.1.0" },
[myapp,
sasl]},
{sys_config, "./config/sys.config"},
{vm_args, "./config/vm.args"},
{dev_mode, true},
{include_erts, false},
{extended_start_script, true}]
}.
{profiles, [{prod, [{relx, [{dev_mode, false},
{include_erts, true}]}]
}]
}.
Here is my myapp.app.src file for completeness:
{application, myapp,
[{description, "An OTP application"},
{vsn, "0.1.0"},
{registered, []},
{mod, { myapp_app, []}},
{applications,
[kernel,
stdlib
]},
{env,[]},
{modules, []},
{maintainers, []},
{licenses, []},
{links, []}
]}.
Requests
Here is a request I'm trying to make from rebar`s shell:
$ ./rebar3 shell
1> ===> Booted myapp
1> ===> Booted sasl
...
1> httpc:request( "http://reddit.com", myapp).
** exception exit: {noproc,
{gen_server,call,
[httpc_myapp,
{request,
{request,undefined,<0.88.0>,0,http,
{"reddit.com",80},
"/",[],get,
{http_request_h,undefined,"keep-alive",undefined,
undefined,undefined,undefined,undefined,undefined,
undefined,...},
{[],[]},
{http_options,"HTTP/1.1",infinity,true,
{essl,[]},
undefined,false,infinity,...},
"http://reddit.com",[],none,[],1478280329839,
undefined,undefined,false}},
infinity]}}
in function gen_server:call/3 (gen_server.erl, line 212)
in call from httpc:handle_request/9 (httpc.erl, line 574)
Here is the request without a profile, to check that inets actually works:
2> httpc:request( "http://reddit.com").
=PROGRESS REPORT==== 4-Nov-2016::13:25:51 ===
supervisor: {local,inet_gethost_native_sup}
started: [{pid,<0.107.0>},{mfa,{inet_gethost_native,init,[[]]}}]
=PROGRESS REPORT==== 4-Nov-2016::13:25:51 ===
supervisor: {local,kernel_safe_sup}
started: [{pid,<0.106.0>},
{id,inet_gethost_native_sup},
{mfargs,{inet_gethost_native,start_link,[]}},
{restart_type,temporary},
{shutdown,1000},
{child_type,worker}]
{ok,{{"HTTP/1.1",200,"OK"},...
rebar3 itself use inets http clients so when It starts your application in shell, inets is already started and configured. One workaround would be stop inets before your application starts, as It's suggested by rebar3 developer (copied below). Another one would be boot your release in console mode:
./_build/default/rel/myapp/bin/myapp console
Beside that there is another problem with your project. You have not told you want inets being started for you. You should have this line in myapp.src:
{applications, [kernel, stdlib, inets]}
Or you can list inets in rebar.config release section, to tell relx this app should be included in release and started on boot.
{relx, [{release, { myapp, "0.1.0" }, [inets, myapp, sasl]} ]}
Stop Inets from Loading on rebar3 shell startup
Here is the copy of the full answer by Fred Hebert from the rebar3 mailing list:
We do need inets for package fetching and will likely not turn it off
automatically for all use cases as this could compromise general usage
of the rebar3 agent in case where the user application does not use
inets, but still asks to fetch packages in a subsequent run. The
workaround I would suggest would be to use a hook script for it. Hook
scripts run before we boot user applications and are regular escripts:
#!/usr/bin/env escript
main(_) -> application:stop(inets).
You can then hook the script in with:
{shell, [{script_file, "path/to/file"}]}
in rebar3.config, or with
rebar3 shell --script_file test/check_env.escript
I can't find anything in the documentation to suggest that rebar.config can contain the application configuration you want.
Instead, application configuration is often kept in a configuration directory in your application, and like the example you gave says, you must use the -config flag when launching erl to point to the configuration file.
If you use rebar3 for making release and start your service by script made with relx (from _build/default/rel/<release_name>/bin/<release_name> by default) the application configuration file is passed to erl for you. If config file exist in your application directory, by default in config/sys.config, It will be regarded as application configuration, otherwise an empty configuration will be made. You can customize Its path by relax' release option sys_config.
For our software, we typically had a single config/sys.config file. The structure is the same as the config sample you have provided. Note that the configuration file can contain settings for many different services. For example, mixing inets with one of ours:
[{inets, [
{services,[{httpc,[{profile, server1}]},
{httpc, [{profile, server2}]}]}
]},
{my_app, [
{my_setting, "my value"}
]}
].
We launch with erl -config config/sys.config.
This way if we need to set service configuration we can simply update our configuration file, which also houses the configuration specific to this application.
As far as I'm aware, this is the correct method to use. I have not been able to find documentation supporting any other way of doing this.

Error running the cowboy application

I am having trouble starting the cowboy application it is giving me following error. For some reason the ranch is not starting, although I have added code to start the ranch in my application.
I see a new git repo cowlib being pulled. but still having trouble.
1> application:start(satomi).
{error,
{bad_return,
{{satomi_app,start,[normal,[]]},
{'EXIT',
{noproc,
{gen_server,call,
[ranch_sup,
{start_child,
{{ranch_listener_sup,http},
{ranch_listener_sup,start_link,
[http,100,ranch_tcp,
[{port,9090}],
cowboy_protocol,
[{...}]]},
permanent,5000,supervisor,
[ranch_listener_sup]}},
infinity]}}}}}}
=INFO REPORT==== 12-Sep-2013::11:42:46 ===
application: satomi
exited: {bad_return,
{{satomi_app,start,[normal,[]]},
{'EXIT',
{noproc,
{gen_server,call,
[ranch_sup,
{start_child,
{{ranch_listener_sup,http},
{ranch_listener_sup,start_link,
[http,100,ranch_tcp,
[{port,9090}],
cowboy_protocol,
[{env,
[{dispatch,
[{'_',[],[{[],[],toppage_handler,[]}]}]}]}]]},
permanent,5000,supervisor,
[ranch_listener_sup]}},
infinity]}}}}}
type: temporary
Following is my app.src
>cat satomi.app.src
{application, satomi,
[
{description, ""},
{vsn, "1"},
{registered, []},
{applications, [
kernel,
stdlib,
cowboy
]},
{mod, { satomi_app, []}},
{env, []}
]}.
>cat satomi.erl
-module(satomi).
-export([start/0]).
start()->
ok = application:start(crypto),
ok = application:start(sasl),
ok = application:start(ranch),
ok = application:start(cowlib),
ok = application:start(cowboy),
ok = application:start(satomi).
I am trying to figure out what's going wrong here
Can anyone point me to the working sample of cowboy that I can use as a template. I am using rebar to compile the code. I don't think that should make any difference.
I am using following command to start the application
erl -pa ./ebin ./deps/*/ebin
When calling application:start(satomi) from the shell it doesn't automatically start the applications it depends on, those need to be started manually.
The satomi:start/0 function you have does exactly this, so the solution is to call satomi:start() from the shell.
The reason is that application:start(satomi) will actually not call satomi:start(), it is a convenience method for starting the application and its dependencies when the application is not part of an Erlang release.
UPDATE: Since Erlang R16B02, there is also application:ensure_all_started. It starts all the dependencies automatically.

Resources