Subiendo api v2

This commit is contained in:
2025-04-16 10:03:13 -03:00
commit 226933fda7
7537 changed files with 576844 additions and 0 deletions

0
deps/logger_file_backend/.fetch vendored Normal file
View File

BIN
deps/logger_file_backend/.hex vendored Normal file

Binary file not shown.

40
deps/logger_file_backend/CHANGELOG.md vendored Normal file
View File

@ -0,0 +1,40 @@
# Changelog
All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [Unreleased]
## v0.0.14
- fix warnings about the use of deprecated :warn
- Bumps versions of `credo` and `ex_doc` to latest
## v0.0.13
- Docs cleanup
- Release file handle
- Bumps versions of `credo` and `ex_doc` to latest
## v0.0.12 - 2021-07-19
- Bumps dependency versions
- Combing through documentation
## v0.0.11 - 2019-08-06
### Enhancements
- Add simple strategy to rotate log files ([3a4d7f](https://github.com/mstratman/logger_file_backend/commit/3a4d7ffea4fd1ea4f4ba2629051efc259dd668ec))
- Allow :all in :metadata option ([#54](https://github.com/onkel-dirtus/logger_file_backend/pull/54))
### Fixes
- Documentation fix ([#39](https://github.com/onkel-dirtus/logger_file_backend/pull/39))
- Eliminate warnings ([#30](https://github.com/onkel-dirtus/logger_file_backend/pull/30), [361c7d](https://github.com/mstratman/logger_file_backend/commit/361c7d81cb408a8aee824d080e16fd26f1920621), [1f0390](https://github.com/mstratman/logger_file_backend/commit/1f0390b29fe90516bd4b70d82250de065900fd41), [#43](https://github.com/onkel-dirtus/logger_file_backend/pull/43))
### Changes
- Update dependencies ([#30](https://github.com/onkel-dirtus/logger_file_backend/pull/30))

21
deps/logger_file_backend/LICENSE.md vendored Normal file
View File

@ -0,0 +1,21 @@
# The MIT License (MIT)
Copyright (c) 2014 Kurt Williams
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

163
deps/logger_file_backend/README.md vendored Normal file
View File

@ -0,0 +1,163 @@
# LoggerFileBackend
[![Module Version](https://img.shields.io/hexpm/v/logger_file_backend.svg)](https://hex.pm/packages/logger_file_backend)
[![Hex Docs](https://img.shields.io/badge/hex-docs-lightgreen.svg)](https://hexdocs.pm/logger_file_backend/)
[![Total Download](https://img.shields.io/hexpm/dt/logger_file_backend.svg)](https://hex.pm/packages/logger_file_backend)
[![License](https://img.shields.io/hexpm/l/logger_file_backend.svg)](https://github.com/onkel-dirtus/logger_file_backend/blob/master/LICENSE.md)
[![Last Updated](https://img.shields.io/github/last-commit/onkel-dirtus/logger_file_backend.svg)](https://github.com/onkel-dirtus/logger_file_backend/commits/master)
A simple Elixir `Logger` backend which writes logs to a file. It does not handle log rotation, but it does tolerate log file renames, so it can be used in conjunction with external log rotation.
**Note** The renaming of log files does not work on Windows, because `File.Stat.inode` is used to determine whether the log file has been (re)moved and, on non-Unix, `File.Stat.inode` is always 0.
**Note** If you are running this with the Phoenix framework, please review the Phoenix specific instructions later on in this file.
## Configuration
`LoggerFileBackend` is a custom backend for the elixir `:logger` application. As
such, it relies on the `:logger` application to start the relevant processes.
However, unlike the default `:console` backend, we may want to configure
multiple log files, each with different log levels, formats, etc. Also, we want
`:logger` to be responsible for starting and stopping each of our logging
processes for us. Because of these considerations, there must be one `:logger`
backend configured for each log file we need. Each backend has a name like
`{LoggerFileBackend, id}`, where `id` is any elixir term (usually an atom).
For example, let's say we want to log error messages to
`"/var/log/my_app/error.log"`. To do that, we will need to configure a backend.
Let's call it `{LoggerFileBackend, :error_log}`.
Our `config.exs` would have an entry similar to this:
```elixir
# tell logger to load a LoggerFileBackend processes
config :logger,
backends: [{LoggerFileBackend, :error_log}]
```
With this configuration, the `:logger` application will start one `LoggerFileBackend`
named `{LoggerFileBackend, :error_log}`. We still need to set the correct file
path and log levels for the backend, though. To do that, we add another config
stanza. Together with the stanza above, we'll have something like this:
```elixir
# tell logger to load a LoggerFileBackend processes
config :logger,
backends: [{LoggerFileBackend, :error_log}]
# configuration for the {LoggerFileBackend, :error_log} backend
config :logger, :error_log,
path: "/var/log/my_app/error.log",
level: :error
```
Check out the examples below for runtime configuration and configuration for
multiple log files.
`LoggerFileBackend` supports the following configuration values:
* `path` - the path to the log file
* `level` - the logging level for the backend
* `format` - the logging format for the backend
* `metadata` - the metadata to include
* `metadata_filter` - metadata terms which must be present in order to log
* metadata_reject - metadata terms which must be present in order to do not log
### Examples
#### Runtime configuration
```elixir
Logger.add_backend {LoggerFileBackend, :debug}
Logger.configure_backend {LoggerFileBackend, :debug},
path: "/path/to/debug.log",
format: ...,
metadata: ...,
metadata_filter: ...
```
#### Application config for multiple log files
```elixir
config :logger,
backends: [{LoggerFileBackend, :info},
{LoggerFileBackend, :error}]
config :logger, :info,
path: "/path/to/info.log",
level: :info
config :logger, :error,
path: "/path/to/error.log",
level: :error
```
#### Filtering specific metadata terms
This example only logs `:info` statements originating from the `:ui` OTP app; the `:application` metadata key is auto-populated by `Logger`.
```elixir
config :logger,
backends: [{LoggerFileBackend, :ui}]
config :logger, :ui,
path: "/path/to/ui.log",
level: :info,
metadata_filter: [application: :ui]
```
This example only writes log statements with a custom metadata key to the file.
```elixir
# in a config file:
config :logger,
backends: [{LoggerFileBackend, :device_1}]
config :logger, :device_1,
path: "/path/to/device_1.log",
level: :debug,
metadata_filter: [device: 1]
# Usage:
# anywhere in the code:
Logger.info("statement", device: 1)
# or, for a single process, e.g., a GenServer:
# in init/1:
Logger.metadata(device: 1)
# ^ sets device: 1 for all subsequent log statements from this process.
# Later, in other code (handle_cast/2, etc.)
Logger.info("statement") # <= already tagged with the device_1 metadata
```
## Additional Phoenix Configurations
Phoenix makes use of its own `mix.exs` file to track dependencies and additional applications. Add the following to your `mix.exs`:
```elixir
def application do
[applications: [
...,
:logger_file_backend,
...
]
]
end
defp deps do
[ ...
{:logger_file_backend, "~> 0.0.10"},
]
end
```
## Copyright and License
Copyright (c) 2014 Kurt Williams
This library licensed under the [MIT license](./LICENSE.md).
## Image Attribution
"log" by Matthew Weatherall from [the Noun Project](https://thenounproject.com/).

BIN
deps/logger_file_backend/assets/logo.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

View File

@ -0,0 +1,15 @@
{<<"links">>,
[{<<"Changelog">>,
<<"https://hexdocs.pm/logger_file_backend/changelog.html">>},
{<<"GitHub">>,<<"https://github.com/onkel-dirtus/logger_file_backend">>}]}.
{<<"name">>,<<"logger_file_backend">>}.
{<<"version">>,<<"0.0.14">>}.
{<<"description">>,<<"Simple logger backend that writes to a file">>}.
{<<"elixir">>,<<"~> 1.0">>}.
{<<"app">>,<<"logger_file_backend">>}.
{<<"licenses">>,[<<"MIT">>]}.
{<<"files">>,
[<<"lib">>,<<"lib/logger_file_backend.ex">>,<<"assets/logo.png">>,
<<"mix.exs">>,<<"README.md">>,<<"CHANGELOG.md">>,<<"LICENSE.md">>]}.
{<<"requirements">>,[]}.
{<<"build_tools">>,[<<"mix">>]}.

View File

@ -0,0 +1,273 @@
defmodule LoggerFileBackend do
@moduledoc """
`LoggerFileBackend` is a custom backend for the elixir `:logger` application.
"""
@behaviour :gen_event
@type path :: String.t()
@type file :: :file.io_device()
@type inode :: integer
@type format :: String.t()
@type level :: Logger.level()
@type metadata :: [atom]
require Record
Record.defrecordp(:file_info, Record.extract(:file_info, from_lib: "kernel/include/file.hrl"))
@default_format "$time $metadata[$level] $message\n"
def init({__MODULE__, name}) do
{:ok, configure(name, [])}
end
def handle_call({:configure, opts}, %{name: name} = state) do
{:ok, :ok, configure(name, opts, state)}
end
def handle_call(:path, %{path: path} = state) do
{:ok, {:ok, path}, state}
end
def handle_event(
{level, _gl, {Logger, msg, ts, md}},
%{level: min_level, metadata_filter: metadata_filter, metadata_reject: metadata_reject} =
state
) do
level = to_logger_level(level)
min_level = to_logger_level(min_level)
if (is_nil(min_level) or Logger.compare_levels(level, min_level) != :lt) and
metadata_matches?(md, metadata_filter) and
(is_nil(metadata_reject) or !metadata_matches?(md, metadata_reject)) do
log_event(level, msg, ts, md, state)
else
{:ok, state}
end
end
def handle_event(:flush, state) do
# We're not buffering anything so this is a no-op
{:ok, state}
end
def handle_info({:EXIT, _pid, _reason}, %{io_device: io_device} = state)
when not is_nil(io_device) do
case File.close(io_device) do
:ok -> {:ok, state}
{:error, reason} -> raise "failure while closing file for reason: #{reason}"
end
end
def handle_info(_, state) do
{:ok, state}
end
# helpers
defp log_event(_level, _msg, _ts, _md, %{path: nil} = state) do
{:ok, state}
end
defp log_event(level, msg, ts, md, %{path: path, io_device: nil} = state)
when is_binary(path) do
case open_log(path) do
{:ok, io_device, inode} ->
log_event(level, msg, ts, md, %{state | io_device: io_device, inode: inode})
_other ->
{:ok, state}
end
end
defp log_event(
level,
msg,
ts,
md,
%{path: path, io_device: io_device, inode: inode, rotate: rotate} = state
)
when is_binary(path) do
if !is_nil(inode) and inode == get_inode(path) and rotate(path, rotate) do
output = format_event(level, msg, ts, md, state)
try do
IO.write(io_device, output)
{:ok, state}
rescue
ErlangError ->
case open_log(path) do
{:ok, io_device, inode} ->
IO.write(io_device, prune(output))
{:ok, %{state | io_device: io_device, inode: inode}}
_other ->
{:ok, %{state | io_device: nil, inode: nil}}
end
end
else
File.close(io_device)
log_event(level, msg, ts, md, %{state | io_device: nil, inode: nil})
end
end
defp rename_file(path, keep) do
File.rm("#{path}.#{keep}")
Enum.each((keep - 1)..1, fn x -> File.rename("#{path}.#{x}", "#{path}.#{x + 1}") end)
case File.rename(path, "#{path}.1") do
:ok -> false
_ -> true
end
end
defp rotate(path, %{max_bytes: max_bytes, keep: keep})
when is_integer(max_bytes) and is_integer(keep) and keep > 0 do
case :file.read_file_info(path, [:raw]) do
{:ok, file_info(size: size)} ->
if size >= max_bytes, do: rename_file(path, keep), else: true
_ ->
true
end
end
defp rotate(_path, nil), do: true
defp open_log(path) do
case path |> Path.dirname() |> File.mkdir_p() do
:ok ->
case File.open(path, [:append, :utf8]) do
{:ok, io_device} -> {:ok, io_device, get_inode(path)}
other -> other
end
other ->
other
end
end
defp format_event(level, msg, ts, md, %{format: format, metadata: keys}) do
Logger.Formatter.format(format, level, msg, ts, take_metadata(md, keys))
end
@doc false
@spec metadata_matches?(Keyword.t(), nil | Keyword.t()) :: true | false
def metadata_matches?(_md, nil), do: true
# all of the filter keys are present
def metadata_matches?(_md, []), do: true
def metadata_matches?(md, [{key, [_ | _] = val} | rest]) do
case Keyword.fetch(md, key) do
{:ok, md_val} ->
md_val in val && metadata_matches?(md, rest)
# fail on first mismatch
_ ->
false
end
end
def metadata_matches?(md, [{key, val} | rest]) do
case Keyword.fetch(md, key) do
{:ok, ^val} ->
metadata_matches?(md, rest)
# fail on first mismatch
_ ->
false
end
end
defp take_metadata(metadata, :all), do: metadata
defp take_metadata(metadata, keys) do
metadatas =
Enum.reduce(keys, [], fn key, acc ->
case Keyword.fetch(metadata, key) do
{:ok, val} -> [{key, val} | acc]
:error -> acc
end
end)
Enum.reverse(metadatas)
end
defp get_inode(path) do
case :file.read_file_info(path, [:raw]) do
{:ok, file_info(inode: inode)} -> inode
{:error, _} -> nil
end
end
defp configure(name, opts) do
state = %{
name: nil,
path: nil,
io_device: nil,
inode: nil,
format: nil,
level: nil,
metadata: nil,
metadata_filter: nil,
metadata_reject: nil,
rotate: nil
}
configure(name, opts, state)
end
defp configure(name, opts, state) do
env = Application.get_env(:logger, name, [])
opts = Keyword.merge(env, opts)
Application.put_env(:logger, name, opts)
level = Keyword.get(opts, :level)
metadata = Keyword.get(opts, :metadata, [])
format_opts = Keyword.get(opts, :format, @default_format)
format = Logger.Formatter.compile(format_opts)
path = Keyword.get(opts, :path)
metadata_filter = Keyword.get(opts, :metadata_filter)
metadata_reject = Keyword.get(opts, :metadata_reject)
rotate = Keyword.get(opts, :rotate)
%{
state
| name: name,
path: path,
format: format,
level: level,
metadata: metadata,
metadata_filter: metadata_filter,
metadata_reject: metadata_reject,
rotate: rotate
}
end
@replacement "<EFBFBD>"
@spec prune(IO.chardata()) :: IO.chardata()
def prune(binary) when is_binary(binary), do: prune_binary(binary, "")
def prune([h | t]) when h in 0..1_114_111, do: [h | prune(t)]
def prune([h | t]), do: [prune(h) | prune(t)]
def prune([]), do: []
def prune(_), do: @replacement
defp prune_binary(<<h::utf8, t::binary>>, acc),
do: prune_binary(t, <<acc::binary, h::utf8>>)
defp prune_binary(<<_, t::binary>>, acc),
do: prune_binary(t, <<acc::binary, @replacement>>)
defp prune_binary(<<>>, acc),
do: acc
defp to_logger_level(:warn) do
if Version.compare(System.version(), "1.11.0") != :lt,
do: :warning,
else: :warn
end
defp to_logger_level(level), do: level
end

63
deps/logger_file_backend/mix.exs vendored Normal file
View File

@ -0,0 +1,63 @@
defmodule LoggerFileBackend.Mixfile do
use Mix.Project
@source_url "https://github.com/onkel-dirtus/logger_file_backend"
@version "0.0.14"
def project do
[
app: :logger_file_backend,
version: @version,
elixir: "~> 1.0",
package: package(),
deps: deps(),
docs: docs()
]
end
def application do
[extra_applications: [:logger]]
end
defp package do
[
description: "Simple logger backend that writes to a file",
maintainers: ["Kurt Williams", "Everett Griffiths"],
licenses: ["MIT"],
files: [
"lib",
"assets/logo.png",
"mix.exs",
"README*",
"CHANGELOG*",
"LICENSE*"
],
links: %{
"Changelog" => "https://hexdocs.pm/logger_file_backend/changelog.html",
"GitHub" => @source_url
}
]
end
defp deps do
[
{:credo, "~> 1.7.5", only: [:dev, :test]},
{:ex_doc, ">= 0.32.1", only: :dev, runtime: false}
]
end
defp docs do
[
extras: [
"CHANGELOG.md": [],
"LICENSE.md": [title: "License"],
"README.md": [title: "Overview"]
],
main: "readme",
source_url: @source_url,
source_ref: "v#{@version}",
logo: "assets/logo.png",
formatters: ["html"]
]
end
end