How can I get all the keys set in my memcached instance(s)?
I tried googling, but didn't find much except that PHP supports a getAllKeys method, which means it is actually possible to do this somehow. How can I get the same within a telnet session?
I have tried out all the retrieval related options mentioned in memcached cheat sheet and Memcached telnet command summary, but none of them work and I am at a loss to find the correct way to do this.
Note: I am currently doing this in development, so it can be assumed that there will be no issues due to new keys being set or other such race conditions happening, and the number of keys will also be limited.
Found a way, thanks to the link here (with the original google group discussion here)
First, Telnet to your server:
telnet 127.0.0.1 11211
Next, list the items to get the slab ids:
stats items
STAT items:3:number 1
STAT items:3:age 498
STAT items:22:number 1
STAT items:22:age 498
END
The first number after ‘items’ is the slab id. Request a cache dump for each slab id, with a limit for the max number of keys to dump:
stats cachedump 3 100
ITEM views.decorators.cache.cache_header..cc7d9 [6 b; 1256056128 s]
END
stats cachedump 22 100
ITEM views.decorators.cache.cache_page..8427e [7736 b; 1256056128 s]
END
memdump
There is a memcdump (sometimes memdump) command for that (part of libmemcached-tools), e.g.:
memcdump --servers=localhost
which will return all the keys.
memcached-tool
In the recent version of memcached there is also memcached-tool command, e.g.
memcached-tool localhost:11211 dump | less
which dumps all keys and values.
See also:
What's the simplest way to get a dump of all memcached keys into a file?
How do I view the data in memcache?
Base on #mu 無 answer here. I've written a cache dump script.
The script dumps all the content of a memcached server. It's tested with Ubuntu 12.04 and a localhost memcached, so your milage may vary.
#!/usr/bin/env bash
echo 'stats items' \
| nc localhost 11211 \
| grep -oe ':[0-9]*:' \
| grep -oe '[0-9]*' \
| sort \
| uniq \
| xargs -L1 -I{} bash -c 'echo "stats cachedump {} 1000" | nc localhost 11211'
What it does, it goes through all the cache slabs and print 1000 entries of each.
Please be aware of certain limits of this script i.e. it may not scale for a 5GB cache server for example. But it's useful for debugging purposes on a local machine.
If you have PHP & PHP-memcached installed, you can run
$ php -r '$c = new Memcached(); $c->addServer("localhost", 11211); var_dump( $c->getAllKeys() );'
Bash
To get list of keys in Bash, follow the these steps.
First, define the following wrapper function to make it simple to use (copy and paste into shell):
function memcmd() {
exec {memcache}<>/dev/tcp/localhost/11211
printf "%s\n%s\n" "$*" quit >&${memcache}
cat <&${memcache}
}
Memcached 1.4.31 and above
You can use lru_crawler metadump all command to dump (most of) the metadata for (all of) the items in the cache.
As opposed to cachedump, it does not cause severe performance problems and has no limits on the amount of keys that can be dumped.
Example command by using the previously defined function:
memcmd lru_crawler metadump all
See: ReleaseNotes1431.
Memcached 1.4.30 and below
Get list of slabs by using items statistics command, e.g.:
memcmd stats items
For each slub class, you can get list of items by specifying slub id along with limit number (0 - unlimited):
memcmd stats cachedump 1 0
memcmd stats cachedump 2 0
memcmd stats cachedump 3 0
memcmd stats cachedump 4 0
...
Note: You need to do this for each memcached server.
To list all the keys from all stubs, here is the one-liner (per one server):
for id in $(memcmd stats items | grep -o ":[0-9]\+:" | tr -d : | sort -nu); do
memcmd stats cachedump $id 0
done
Note: The above command could cause severe performance problems while accessing the items, so it's not advised to run on live.
Notes:
stats cachedump only dumps the HOT_LRU (IIRC?), which is managed by a background thread as activity happens. This means under a new enough version which the 2Q algo enabled, you'll get snapshot views of what's in just one of the LRU's.
If you want to view everything, lru_crawler metadump 1 (or lru_crawler metadump all) is the new mostly-officially-supported method that will asynchronously dump as many keys as you want. you'll get them out of order but it hits all LRU's, and unless you're deleting/replacing items multiple runs should yield the same results.
Source: GH-405.
Related:
List all objects in memcached
Writing a Redis client in pure bash (it's Redis, but very similar approach)
Check other available commands at https://memcached.org/wiki
Check out the protocol.txt docs file.
The easiest way is to use python-memcached-stats package, https://github.com/abstatic/python-memcached-stats
The keys() method should get you going.
Example -
from memcached_stats import MemcachedStats
mem = MemcachedStats()
mem.keys()
['key-1',
'key-2',
'key-3',
... ]
I was using Java's spyMemcached, and used this code. It is based on Anshul Goyal's answer
#Autowired
#Qualifier("initMemcachedClient")
private MemcachedClient memcachedClient;
public List<String> getCachedKeys(){
Set<Integer> slabIds = new HashSet<>();
Map<SocketAddress, Map<String, String>> stats;
List<String> keyNames = new ArrayList<>();
// Gets all the slab IDs
stats = memcachedClient.getStats("items");
stats.forEach((socketAddress, value) -> {
System.out.println("Socket address: "+socketAddress.toString());
value.forEach((propertyName, propertyValue) -> {
slabIds.add(Integer.parseInt(propertyName.split(":")[1]));
});
});
// Gets all keys in each slab ID and adds in List keyNames
slabIds.forEach(slabId -> {
Map<SocketAddress, Map<String, String>> keyStats = memcachedClient.getStats("cachedump "+slabId+" 0");
keyStats.forEach((socketAddress, value) -> {
value.forEach((propertyName, propertyValue) -> {
keyNames.add(propertyName);
});
});
});
System.out.println("number of keys: "+keyNames.size());
return keyNames;
}
Java Solution:
Thanks! #Satvik Nema
Your solution helped me to find the approach, but it doesn't work for memcached 2.4.6 version. (implementation 'com.googlecode.xmemcached:xmemcached:2.4.6')
Not sure when did new method getStatsByItem included.
I figured out required changes using documentation and below code worked for me.
// Gets all the slab IDs
Set<Integer> slabIds = new HashSet<>();
Map<InetSocketAddress, Map<String, String>> itemsMap = null;
try {
itemsMap = this.memcachedClient.getStatsByItem("items");
} catch (Exception e) {
log.error("Failed while pulling 'items'. ERROR", e);
}
if (Objects.nonNull(itemsMap)) {
itemsMap.forEach((key, value) -> {
log.info("itemsMap {} : {}", key, value);
value.forEach((k, v) -> {
slabIds.add(Integer.parseInt(k.split(":")[1]));
});
});
}
// Gets all keys in each slab ID and adds in List keyNames
slabIds.forEach(slabId -> {
Map<InetSocketAddress, Map<String, String>> keyStats = null;
try {
keyStats = this.memcachedClient.getStatsByItem("cachedump " + slabId + " 0");
} catch (Exception e) {
log.error("Failed while pulling 'cachedump' for slabId: {}. ERROR", slabId, e);
}
if (Objects.nonNull(keyStats)) {
keyStats.forEach((socketAddress, value) -> {
value.forEach((propertyName, propertyValue) -> {
//keyNames.add(propertyName);
log.info("keyName: {} Value: {}", propertyName, propertyValue);
});
});
}
});
Related
I have this issue
*********** codeception.yml ***************
paths:
tests: tests
output: tests/_output
data: tests/_data
support: tests/_support
envs: tests/_envs
actor_suffix: Tester
#amount customer per product
amountPerProduct: 1
wishCountry: 1
wishProduct: 0
I am using the param like this:
$countryIndex = Configuration::config()['wishCountry'];
but on the console I calling the test like this:
codecept run tests/acceptance/ChangeCest.php --env chrome --xml --html -o "wishProduct:55"
I get this error:
enter image description here
QUESTION: how can I override this config in Gitlab?
Thank you
Not entirely sure if this solves your problem but for Codeception v5 (also my current local version v4.2.1) the option is exploded with : , i.e. with an appended space. I notice in your screenshot the exception does show the key/value without the space in between, but you didn't specify which version of Codeception you're using.
From Config.php:
foreach ($configOptions as $option) {
$keys = explode(': ', $option);
// ^ notice the space here
if (count($keys) < 2) {
throw new \InvalidArgumentException('--override should have config passed as "key: value"');
}
https://github.com/Codeception/Codeception/blob/5.0/src/Codeception/Command/Shared/ConfigTrait.php
i find the answer to my problem.
I store the parameters in a new file params.yml
params.yml
parameters:
WISH_PRODUCT: 55
codeception.yml
params:
- params.yml
acceptance.suite.yml
config:
custom_params:
wishProduct: %WISH_PRODUCT%
AcceptanceTester.php
so in AcceptanceTester I can read the values like this
$custom_params = Configuration::suiteSettings('acceptance', Configuration::config())['modules']['custom_params'];
So I am trying to get battery status from linux, and so far the first command (path variable) returns perfectly and I am able to get its response in form of Sequence from the input stream, but unfortunately the second command (of result variable) returns empty sequence.
fun getLinuxBatteryStatus(): Nothing? {
val path = """upower --enumerate""".runCommand() ?: return null
val parameters = listOf("present", "state", "energy-full", "energy", "energy-rate", "time to empty", "percentage")
val result = """upower -i ${path.first { "battery_BAT" in it }} | grep -E "${parameters.joinToString("|")}""""
.also { println(it) }
.runCommand() ?: return null
result.forEach(::println) // <- no ouput
// println(result.count()) // <- 0
/* Do other thing and return something (that is not related to problem) */
}
Ouput:
upower -i /org/freedesktop/UPower/devices/battery_BAT1 | grep -E "present|state|energy-full|energy|energy-rate|time to empty|percentage"
The above output is from the also block in the last command, just to preview the command's string for debugging. And if I run the above command directly into the terminal I am successfully getting the responses as follows:
present: yes
state: charging
energy: 47.903 Wh
energy-empty: 0 Wh
energy-full: 50.299 Wh
energy-full-design: 48.004 Wh
energy-rate: 17.764 W
percentage: 95%
Why is the last command not working (not returning any response) with the ProcessBuilder?
Note: the extension function runCommand has been taken from here
private fun String.runCommand(
workingDir: File = File("."),
timeoutAmount: Long = 60,
timeoutUnit: TimeUnit = TimeUnit.SECONDS
): Sequence<String>? = try {
ProcessBuilder(split("\\s".toRegex()))
.directory(workingDir)
.redirectOutput(ProcessBuilder.Redirect.PIPE)
.redirectError(ProcessBuilder.Redirect.PIPE)
.start()
.apply { waitFor(timeoutAmount, timeoutUnit) }
.inputStream.bufferedReader().lineSequence()
} catch (e: IOException) {
e.printStackTrace()
null
}
The problem here is the pipe.
You're trying to run a pipeline — a construction involving running multiple programs, that needs a shell to interpret.
But ProcessBuilder runs a single program. In this case, it's running the program upower and passing it the parameters -i, /org/freedesktop/UPower/devices/battery_BAT1, |, grep, -E, and "present|state|energy-full|energy|energy-rate|time to empty|percentage". Obviously upower won't know what to do with the | parameter or those after it.
You could use ProcessBuilder to run up a shell instance, which could then run your pipeline; see this answer.
But it would probably be simpler, safer, and more efficient to do the filtering in your own code, and avoid calling grep entirely.
I recommend capturing the process's error output, which would very probably have made the problem clear.
I'm using puppet 5 and writing a module which refers to some hiera which has some duplication in it (example below - see gpgkey):
profile::example1:
repo1:
descr: Centos repo
gpgkey: file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-7
repo2:
descr: Centos repo
gpgkey: file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-7
repo3:
descr: puppet repo
gpgkey: http://puppet.repo/GPG-KEY
I've successfully managed to retrieve the repo names (repo1, repo2 and repo3 in this example). What I'd like to do next is run an exec to import the gpgkey, however this is failing with a duplicate declaration error (I assume because the gpgkey is duplicated in the hiera). Any ideas or help on how to do this? Here's the lookup:
$repo_name = lookup('profile::example1', Hash, 'deep')
$repo_name.each | $name, Hash $config_hash | {
notify { "${name}": }
}
I've looked at embedding another loop to pull values from $config_hash but I usually get the same result regardless.
Puppet's built-in unique() function seems natural for this job. For example:
$repos = lookup('profile::example1', Hash, 'deep')
$unique_keys = $repos.map |$_name, $props| { $props['gpgkey'] } .unique
$unique_keys.each |$key| {
# ...
}
Can you think of a way to solve this problem in Puppet?
I have a custom fact with generates a string of IP addresses depending on the domain it is run on, it can resolve to have 1 to n addresses.
"10.1.29.1"
"10.1.29.1,10.1.29.5"
"10.1.29.1,10.1.29.5,10.1.29.7"
etc
I want to add these to the host file with a generated server names of servernameX for example;
10.1.29.1 myservername1
10.1.29.5 myservername2
10.1.29.7 myservername3
So how can you do this as puppet doesn't have an array iterator like "for each"?
Sadly, even if you go about and use a custom "define" to iterate over an array upon splitting your custom fact on a comma, the result will be rather not what you expect and not even close to a "for each" loop -- aside of causing you a headache, probably.
Said that, I am not sure if this is what you want to achieve, but have a look at this approach:
$fact = '1.1.1.1,2.2.2.2,3.3.3.3'
$servers = split($::fact, ',')
$count = size($servers)
$names = bracket_expansion("host[01-${count}].address")
file { '/tmp/test.txt':
content => inline_template('<%= #servers.each_with_index.map {|v,i| "#{v}\t\t#{#names[i]}\n" } %>'),
ensure => present
}
What we have there are two custom functions: size() and bracket_expansion(); which we then use values that they provide inside a hack that leverages the inline_template() function to render content of the file utilising parallel access to two arrays -- one with IP addresses from your fact and one with host names that should follow.
The result is a follows:
matti#acrux ~ $ cat | puppet apply
$fact = '1.1.1.1,2.2.2.2,3.3.3.3'
$servers = split($::fact, ',')
$count = size($servers)
$names = bracket_expansion("host[01-${count}].address")
file { '/tmp/test.txt':
content => inline_template('<%= #servers.each_with_index.map {|v,i| "#{v}\t\t#{#names[i]}\n" } %>'),
ensure => present
}
notice: /Stage[main]//File[/tmp/test.txt]/ensure: created
notice: Finished catalog run in 0.07 seconds
matti#acrux ~ $ cat /tmp/test.txt
1.1.1.1 host01.address
2.2.2.2 host02.address
3.3.3.3 host03.address
matti#acrux ~ $
Both size() and bracket_expansion() functions can be found here:
https://github.com/kwilczynski/puppet-functions/tree/master/lib/puppet/parser/functions/
I hope this helps a little :-)
Is there a way to parse thru a txt file that includes elements seperated by {}s
Here is a sample from the file:
virtual vs_devtnet_80 {
snat automap
pool pool_devtnet_80
destination 167.69.107.41:http
ip protocol tcp
profiles {
profile_http_health {}
tcp-lan-optimized {}
}
}
virtual vs_devdpp_4430 {
snat automap
pool pool_devdpp_5430
destination 167.69.107.31:https
ip protocol tcp
persist devdpp
profiles tcp-lan-optimized {}
}
virtual vs_devwww30_80 {
snat automap
pool pool_devwww30_80
destination 167.69.107.46:http
ip protocol tcp
profiles {
profile_http_health {}
tcp-lan-optimized {}
}
}
As you can see, the elements are separated, but with {}
Any help would be gladly appreciated. I was trying to use grep but it only returns one line...
I would like to be able to search by the top most element, for example searh.sh virtual vs_devtnet_80, and have it return the entire blob..furthermore perhaps be able to search for botht eh top layer and one of its sub layers, for example search.sh virtual vs_devtnet_80 pool which would return pool_devtnet_80
Something like:
cat .tmp | sed '/.*{/ ! { s/.*//g}'
this wont solve it completely, but i think it does something similar to what you want
Look at JSON pasers, they're written in all sort of languages, syntax looks similar enough to give you some ideas on how to tackle this.
Basically what you need to do is have a recursive function that calls itself whenever it encounters a '{' and returns the content whenever it encounters a '}'.
I wrote an article on a lisp-like parser that actually does just that. Check it out here for inspiration: http://www.codeproject.com/KB/linq/TinyLisp.aspx
Rgds Gert-Jan
This is Tcl syntax, so you can set up a mechanism to run it as a Tcl script that creates a data structure of itself.
#!/usr/bin/env tclsh
# create a safe slave interpreter
set slave [interp create -safe]
# set up the slave to parse the input file
$slave eval {
proc virtual {subkey body} {
eval $body
}
proc unknown {cmd args} {
upvar 1 subkey subkey ;# access the 'subkey' variable from the 'virtual' proc
if {[llength $args] == 1} {set args [lindex $args 0]}
dict set ::data $subkey $cmd $args
}
set data [dict create]
}
$slave expose source
# now do the parsing in the slave
$slave eval source [lindex $argv 0]
# fetch the data structure
set data [$slave eval set data]
# and do stuff with it.
dict for {subkey subdict} $data {
puts "$subkey destination = [dict get $subdict destination]"
}
And then, parser.tcl input_file outputs
vs_devaetnet_80 destination = 167.69.107.41:http
vs_devdpp_4430 destination = 167.69.107.31:https
vs_devwww30_80 destination = 167.69.107.46:http
This should give you the 2nd 'blob', for instance:
sed -n '/virtual vs_devdpp_4430.*/,/^}$/p' filename.txt
and pipe through grep -oP '(?<=pool ).*' to get what follows pool in that blob.
I ended up having to create a recursive function that first used strpos to find the search variable within the entire config file. Then using a recursive function pop'd on and pop'd off brackets to return the searched variable's entire body.