I've been using Spray for a while and I'm trying to match a URI that looks like this:
http GET http://127.0.0.1:8080/sec/company/file/txt/2012QTR1/0000018255-12-000005_finalDoc.html
The DSL that I wrote is like this:
pathPrefix("sec") {
//...some other routes
pathPrefix("company") {
pathPrefix("file") {
path("txt" / Segment) { fileName =>
get {
complete(fileName)
}
} ~
path("html" / Segment) { fileName =>
get {
complete(fileName)
}
} ~ complete(NotFound)
}
}
I'm trying to match 2012QTR1/0000018255-12-000005_finalDoc.html which can be then converted into an actual path to the requested file.
I noticed the ("txt" / Segment) can only match a URI with one segment, not the whole string, but how can I match the rest of the text without having to write something like ("txt" / Segment / Segment / Segment)?
You need to use Rest or RestPath instead. From the docs:
Rest: PathMatcher1[String] Matches and extracts the complete remaining
unmatched part of the request’s URI path as an (encoded!) String. If
you need access to the remaining decoded elements of the path use
RestPath instead.
RestPath: PathMatcher1[Path] Matches and extracts
the complete remaining, unmatched part of the request’s URI path.
Related
I have used Rails filter parameters to not print out the cities and States in the logs.
Rails.application.config.filter_parameters += [:city, :state]
However, I have a custom log that is getting incorrectly filtered and I need it to get printed:
Rails.logger.info("Transaction state has changed.", state: transaction.state)
How can I force this hash to bypass the parameter filtering?
I don't believe there is a way to ignore specific filters, however you can make the filter less generic. They are more generic than it seems.
Each entry in Rails.application.config.filter_parameters is actually an argument to ActiveSupport::ParameterFilter.new.
This takes two types of filters: Regexes and Proc. Everything else is converted to a Regex.
Rails.application.config.filter_parameters += [:city, :state] is really the very generic Rails.application.config.filter_parameters += [/city/i, /state/i]. That will match state_of_mind and specificity which is probably not what you had in mind.
pf = ActiveSupport::ParameterFilter.new([:city, :state])
p pf.filter({specificity: 42, state_of_mind: "confused"})
# {:specificity=>"[FILTERED]", :state_of_mind=>"[FILTERED]"}
You can match specific models with model.param.
Rails.application.config.filter_parameters += ["user.city", "user.state"]
This will match { user: { state: "..."} } (user.state) and not { transaction: { state: "..." } } (transaction.state).
However, these are still unanchored regex matches, so it will match { admin_user: { state_of_mind: "..." } } (admin_user.state_of_mind).
To avoid this, use a full regex.
Rails.application.config.filter_parameters += [/^user\.(city|state)$/]
You can also use a function for more control. This takes the key, value, and original parameters. These are a bit awkward.
The "key" is only the immediate key so { transaction: { state: "..." } } will only get :state.
The value itself must be changed.
Rails.application.config.filter_parameters << ->(key,value,original_params) do
p key
p value
p original_params
v.replace("[FILTERED]") if key.to_s.match(/^(city|state)$/i)?
end
So, I have an array of Genre objects that contain name properties that are Strings that I want a UILabel.text to contain the values.
Id like the label to look something like this ultimately:
String[0] / String[1] / String[2] / String[3]
with the front slashes separating the strings. I can get the label to contain the values, and I can even get the / separators, but my logic is flawed as after the last string I still get the front slash.
Can someone help me with the logic where it will add the string and a front slash unless its the last item in the array and if its the last item in the array it should just add the string and no front slash.
Right now I just have a simple For In loop
if game?.genres?[0].name == nil {
for genre in game!.genres! {
genreLabel.text! += "\(genre.name!) / "
}
}
Ive tried
game.genres.map { $0.name }.joined(separator: “ / “)
but that gives an error of:
Value of type '[Genre]' has no member 'name'
What is the logic here to do something different with the last element?
Because you didn't use enough questions marks, the compiler thinks you're using Optional.map instead of Array.map.
You can get the result you want, like this:
game?.genres?.compactMap(\.name).joined(separator: " / ")
…but you're using too many optionals. Just make genres non-optional. An array can already be empty. It doesn't also need to be nil.
game?.genres.compactMap(\.name).joined(separator: " / ")
…and if you can, make game and name non-optional too.
game.genres.map(\.name).joined(separator: " / ")
You can achieve this by using index
for (index,genre) in game!.genres!.enumerated() {
genreLabel.text! += "\(genre.name!) / "
if index == game!.genres!.count -1 {
// do something with last index
}
}
I am reading data from files by defining path as *.log etc,
Files names are like app1a_test2_heep.log , cdc2a_test3_heep.log etc
How to configure logstash so that the part of string that is string before underscore (app1a, cdc2a..) should be grepped and added to host field and removing the default host.
Eg:
fileName: app1a_test2_heep.log
host => app1a
Thanks in advance,
Ravi
Ruby filter can do what you want.
input {
file {
path => "/home/benlim/app1a_test2_heep.log"
}
}
filter {
ruby {
code => "
filename = event['path'].split('/').last
event['host'] = filename.split('_').first
"
}
}
output {
stdout { codec => rubydebug }
}
First, get the filename from the path. Then, get the hostname.
You can gsub (substitute) in mutate filter. It takes 3 arguments - field, what to sub and on what. You can use regexp here.
filter {
mutate {
gsub => [
# replace all after slashes with nothing
"host", "[_.*]", ""
]
}
}
I have raw data that is contained in 3 separate lines. I want to build a single map record using parts of each line. I then read the next 3 lines and create the next map record and so on. All the groovy examples I've found on maps show them being created from data on a single line, or possibly i am misunderstanding the examples. Here is what the raw data looks like.
snmp v2: data result = "Local1"
snmp v2: data result ip = "10.10.10.121"
snmp v2: data result gal = "899"
new
snmp v2: data result = "Local2"
snmp v2: data result ip = "192.168.10.2"
snmp v2: data result gal = "7777"
new
I want to put this data into a map. In this example Local1 and Local2 would be keys and they would each have 2 associated values. I will show you my latest attempt but it is little more then a guess that failed.
def data = RAW
def map = [:]
data.splitEachLine("="){
it.each{ x ->
map.put(it[0], it[1])
map.each{ k, v -> println "${k}:${v}" } }}
The desired output is:
[ Local1 : [ ip: "10.10.10.121", gal: "899" ],
Local2: [ ip: "192.168.10.2", gal: "7777" ] ]
You can build a new data structure from an existing one using aggregate operations defined on collections; collect produces a list from an existing list, collectEntries creates a map from a list.
The question specifies there are always three lines for an entry, followed by a line with "new" on it. If I can assume they're always in the same order I can grab the last word off each line, use collate to group every four lines into a sublist, then convert each sublist to a map entry:
lines = new File('c:/temp/testdata.txt').readLines()
mymap = lines.collect { it.tokenize()[-1] }
.collate(4)
.collectEntries { e-> [(e[0].replace('"', ''))) : [ip: e[1], gal: e[2]]] }
which evaluates to
[Local1:[ip:"10.10.10.121", gal:"899"], Local2:[ip:"192.168.10.2", gal:"7777"]]
or remove all the quotes in the first step:
mymap = lines.collect { (it.tokenize()[-1]).replace('"', '') }
.collate(4)
.collectEntries { e-> [(e[0]) : [ip: e[1], gal: e[2]]] }
in order to get
[Local1:[ip:10.10.10.121, gal:899], Local2:[ip:192.168.10.2, gal:7777]]
If you want to get a nested map as suggested by dmahapatro try this:
def map = [:]
data=data.eachLine() { line ->
if(line.startsWith("new")) return
tokens=line.replace("snmp v2: data","").split("=")
tokens=tokens.collect() { it.trim().replace("result ","").replaceAll(/"/, "") }
if(tokens[0]=="result") {
nested=[:]
map[tokens[1]]=nested
}
else
nested[tokens[0]]=tokens[1]
}
println("map: $map")
here we:
iterate over lines
skip lines with "new" at the beginning
remove "snmp v2: data" from the text of the line
split each line in tokens, trim() each token, and remove "result " and quotes
tokens are in pairs and now look like:
result, Local1
ip, 10.10.10.121
gal, 899
next when the first token is "result", we build a nested map and place in the main map at the key given by the value of token[1]
otherwise we populate the nested map with key=token[0] and value=token[1]
the result is:
map: [Local1:[ip:10.10.10.121, gal:899], Local2:[ip:192.168.10.2, gal:7777]]
edit: fixed to remove quotes
Assume I have:
visit(p) {
case ...
default:
println("This should not happen. All elements should be catched. Check: <x>");
};
How can I print out (in this case as x) what could not be matched?
I tried:
x:default:
\x:default:
default:x:
\default:x:
Tx,
Jos
We have a library named Traversal that allows you to get back the context of a match. So, you can do something like this:
import Traversal;
import IO;
void doit() {
m = (1:"one",2:"two",3:"three");
bottom-up visit(m) {
case int n : println("<n> is an int");
default: {
tc = getTraversalContext();
println("Context is: <tc>");
println("<tc[0]> is not an int");
if (str s := tc[0]) {
println("<s> is a string");
}
}
}
}
tc is then a list of all the nodes back to the top of the term -- in this case, it will just be the current value, like "three", and the entire value of map m (or the entire map, which will also be a match for the default case). If you had something structured as a tree, such as terms formed using ADTs or nodes, you would get all the intervening structure from the point of the match back to the top (which would be the entire term).
For some reason, though, default is matching the same term multiple times. I've filed this as bug report https://github.com/cwi-swat/rascal/issues/731 on GitHub.
You could also try this idiom:
visit(x) {
case ...
case ...
case value x: throw "default case should not happen <x>";
}
The value pattern will catch everything but only after the others are tried.