diff --git a/README.md b/README.md
index 233aef6..a540b14 100644
--- a/README.md
+++ b/README.md
@@ -30,5 +30,6 @@ These services may need to be configured in order to enable mu-cache support. Ch
## Debugging
Debugging of cache keys is helped by following environment variables:
+ - `LOG_CACHE_CLEAR_EVENT`: Store cache clear events in the database
- `LOG_CACHE_KEYS`: Logs received cache key to a response
- `LOG_CLEAR_KEYS`: Logs received clear keys either as a response, or explicitly received through ./mu/delta.
diff --git a/config/config.exs b/config/config.exs
index 7e440ca..b777a4e 100644
--- a/config/config.exs
+++ b/config/config.exs
@@ -21,6 +21,7 @@ end
# 3rd-party users, it should be done in your "mix.exs" file.
config :mu_cache,
+ log_cache_clear_event: CH.system_boolean("LOG_CACHE_CLEAR_EVENT"),
log_cache_keys: CH.system_boolean("LOG_CACHE_KEYS"),
log_clear_keys: CH.system_boolean("LOG_CLEAR_KEYS")
diff --git a/lib/cache/cache.ex b/lib/cache/cache.ex
index 201360e..7c2ad22 100644
--- a/lib/cache/cache.ex
+++ b/lib/cache/cache.ex
@@ -93,13 +93,18 @@ defmodule Cache.Registry do
# We have multiple clear_keys and need to update the state for it.
%{cache: cache, caches_by_key: caches_by_key} = state
+ # IO.inspect(clear_keys, label: "Clearing these keys")
+ # IO.inspect(cache, label: "Cache before clearing the keys")
+
cache =
Enum.reduce(clear_keys, cache, fn clear_key, cache ->
keys_to_remove = Map.get(caches_by_key, clear_key, [])
+ maybe_send_cleared_key_to_database!(keys_to_remove)
cache = Map.drop(cache, keys_to_remove)
cache
end)
+ # IO.inspect(cache, label: "Cache after clearing the keys")
caches_by_key = Map.drop(caches_by_key, clear_keys)
%{state | cache: cache, caches_by_key: caches_by_key}
@@ -135,4 +140,31 @@ defmodule Cache.Registry do
%{state | cache: cache}
end
+
+ defp maybe_send_cleared_key_to_database!(request_key_to_remove) do
+ # Write to the database when a cache for a url is cleared
+ if Application.get_env(:mu_cache, :log_cache_clear_event) do
+ Enum.map(request_key_to_remove, fn req_key ->
+ {method, path, query, auth} = req_key
+ uuid = Support.generate_uuid()
+ auth_escaped = Support.sparql_escape(auth)
+ query = """
+ PREFIX mu:
+ PREFIX mucache:
+ INSERT DATA {
+ GRAPH {
+ a mucache:CacheClear ;
+ mu:uuid "#{uuid}";
+ mucache:path "#{path}";
+ mucache:method "#{method}";
+ mucache:query "#{query}";
+ mucache:muAuthAllowedGroups \"\"\"#{auth_escaped}\"\"\";
+ mucache:muAuthUsedGroups \"\"\"#{auth_escaped}\"\"\".
+ }
+ }
+ """
+ Support.update(query)
+ end)
+ end
+ end
end
diff --git a/lib/manipulators/cache_key_logger.ex b/lib/manipulators/cache_key_logger.ex
index cdc5e54..7f35965 100644
--- a/lib/manipulators/cache_key_logger.ex
+++ b/lib/manipulators/cache_key_logger.ex
@@ -38,7 +38,9 @@ defmodule Manipulators.CacheKeyLogger do
end
defp header_value(headers, header_name) do
- header = Enum.find(headers, header_name)
+ header =
+ headers
+ |> Enum.find({nil, "[]"}, &match?({header_name, _}, &1))
if header do
elem(header, 1)
diff --git a/lib/support.ex b/lib/support.ex
new file mode 100644
index 0000000..75e40fa
--- /dev/null
+++ b/lib/support.ex
@@ -0,0 +1,63 @@
+# Note: this is copied from https://github.com/mu-semtech/mu-elixir-template should be replaced by integrating the template
+defmodule Support do
+ # environment variables
+ def sparql_endpoint() do
+ System.get_env("MU_SPARQL_ENDPOINT")
+ end
+ def application_graph() do
+ System.get_env("MU_APPLICATION_GRAPH")
+ end
+ def sparql_timeout() do
+ System.get_env("MU_SPARQL_TIMEOUT")
+ end
+ def log_level() do
+ System.get_env("LOG_LEVEL")
+ end
+
+ # uuid helper
+ def generate_uuid() do
+ UUID.uuid4()
+ end
+
+ # graph helper
+ def graph() do
+ application_graph()
+ end
+
+ # query helper
+ def _query_get_URL(escaped_query_string) do
+ if sparql_timeout() > 0 do
+ "#{sparql_endpoint()}?query=#{escaped_query_string}&timeout=#{sparql_timeout()}"
+ else
+ "#{sparql_endpoint()}?query=#{escaped_query_string}"
+ end
+ end
+
+ def query(query_string) do
+ query_string
+ |> URI.encode
+ |> _query_get_URL
+ |> HTTPoison.get!([{"Accept", "application/json"}])
+ |> ( &( &1.body ) ).()
+ |> Poison.decode!
+ end
+
+ def update(query_string) do
+ HTTPoison.post!(
+ sparql_endpoint(),
+ [
+ "query=" <>
+ URI.encode_www_form(query_string) <>
+ "&format=" <> URI.encode_www_form("application/sparql-results+json")
+ ],
+ ["Content-Type": "application/x-www-form-urlencoded"],
+ []
+ )
+ |> ( &( &1.body ) ).()
+ |> Poison.decode!
+ end
+
+ def sparql_escape(value) do
+ String.replace(value, "\"", "\\\"")
+ end
+end
diff --git a/mix.exs b/mix.exs
index 41e47b0..8103c71 100644
--- a/mix.exs
+++ b/mix.exs
@@ -48,7 +48,9 @@ defmodule UsePlugProxy.Mixfile do
{:plug_cowboy, "~> 2.4.1"},
{:dialyxir, "~> 1.0", only: [:dev], runtime: false},
{:credo, "~> 1.5", only: [:dev, :test], runtime: false},
- {:poison, "~> 2.0"}
+ {:poison, "~> 2.0"},
+ {:uuid, "~> 1.1"},
+ {:httpoison, "~> 1.5"}
]
end
end