覚えたら書く

IT関係のデベロッパとして日々覚えたことを書き残したいです。twitter: @yyoshikaw

Go言語 - システム情報を取得する

Golangで、システム情報というかOSのuptime(稼働時間)が取得したかったんですが、
Go sigarを利用すると楽そうだったのでお世話になります。


とりあえず、ライブラリのダウンロードを行います

go get github.com/cloudfoundry/gosigar


uptimeとか取得してみる

そして早速サンプルコードですが、uptimeだけ取得しても寂しかったので、ロードベレージやメモリの使用率なども取得してみました。


■サンプルコード

package main

import (
    "fmt"

    "github.com/cloudfoundry/gosigar"
)

func main() {
    uptime := sigar.Uptime{}
    uptime.Get()

    // uptime
    fmt.Printf("Uptime: %s \n", uptime.Format())

    avg := sigar.LoadAverage{}
    avg.Get()

    // ロードアベレージ(1分、5分、15分)
    fmt.Printf("Load average: %.2f, %.2f, %.2f\n", avg.One, avg.Five, avg.Fifteen)

    mem := sigar.Mem{}
    mem.Get()

    // メモリ使用量
    fmt.Printf("Mem(MB): total=%d, used=%d, free=%d\n", formatMB(mem.Total), formatMB(mem.Used), formatMB(mem.Free))
}

func formatMB(val uint64) uint64 {
    return val / 1024 / 1014
}


■実行結果

Uptime: 46 days, 11:56
Load average: 1.52, 1.58, 1.82
Mem(MB): total=16545, used=9082, free=7463


まとめ

簡単にuptime等、一部のシステム情報を無事に取得することができました。



関連エントリ

Windows 10 - All Users のスタートアップフォルダを開く

Windows 7 だとAll Users のスタートアップフォルダの場所にExplorerなんかでも簡単に行きつけるんですが、Windows 10 だとすぐ迷子になってしまいます(行きつけません)。

というわけで、今後迷子にならないためのメモです。

場所は通常であれば以下パスになります

C:\ProgramData\Microsoft\Windows\Start Menu\Programs\StartUp


ふー、これさえメモっておけば一安心。

と、これだけでも良かったんですが、なんとExplorerで以下を入力してEnter押すだけでも行きつけるようです。全然知らなかった。
(それも、Windows 7でも利用可能!)

shell:Common Startup


実際やってみた感じは以下のようになりました

Explorer開いて、shell:Common Startupと入力してEnterキー押すと f:id:nini_y:20181106232548p:plain

ばっちり All Users のフォルダが開かれました。 f:id:nini_y:20181106232934p:plain


楽だ。これからは、これでやっていこう

Go言語 - 置換文字列を一部置換しなかったらどうなるの?

fmt.Sprintf などでフォーマット文字列を置換する場合に、置換対象のパラメータが複数あることもあります。
その際に、置換すべき値の数が合わないとどうなってしまうのかな?と思って一応試してみました。

http://127.0.0.1:%d/%s というフォーマット用の文字列があって、ポート番号とコンテキストパスにあたる部分の値を与えて、URLを完成させたい
という例で試してみます


正しく置換する

フォーマット上の変数の数と置換する値を合わせます


■サンプルコード

import "fmt"

func main() {
    fmtString := "http://127.0.0.1:%d/%s"
    result0 := fmt.Sprintf(fmtString, 8080, "app")
    fmt.Printf("0-A >> Format replace value. [%s] -> [%s]\n", fmtString, result0)
}


■実行結果

0-A >> Format replace value. [http://127.0.0.1:%d/%s] -> [http://127.0.0.1:8080/app]

ほしかった文字列が得られています。


パラメータに対して値が不足している

フォーマット上の変数の数に対して置換する値の数が少なかった場合にどうなるか試してみます。


■サンプルコード

import "fmt"

func main() {
    fmtString := "http://127.0.0.1:%d/%s"
    result1 := fmt.Sprintf(fmtString, 8080)
    fmt.Printf("1-A >> Format replace value. [%s] -> [%s]\n", fmtString, result1)
}


■実行結果

1-A >> Format replace value. [http://127.0.0.1:%d/%s] -> [http://127.0.0.1:8080/%!s(MISSING)]

置換すべき値が無かった場合、置換用の記述(今回の場合 %s)のまま残ったりしないかななんて期待しましたが、そんなアホなことはありませんでした。
不足してた部分が、 %!s(MISSING) という文字列になってしまっています。


パラメータに対して値が多い

フォーマット上の変数の数に対して置換する値の数が多かった場合にどうなるか試してみます。


■サンプルコード

import "fmt"

func main() {
    fmtString := "http://127.0.0.1:%d/%s"
    result2 := fmt.Sprintf(fmtString, 8080, "app", "/dummy")
    fmt.Printf("2-A >> Format replace value. [%s] -> [%s]\n", fmtString, result2)
}


■実行結果

2-A >> Format replace value. [http://127.0.0.1:%d/%s] -> [http://127.0.0.1:8080/app%!(EXTRA string=/dummy)]

多くて余ってしまう値(置換部分に当てはまらない値)のことは無視してくれるかなとか期待しましたが、そんなアホなことはありませんでした。
余計な値の分、 %!(EXTRA string=/dummy) という文字列が付与された結果になってしまっています。


まとめ

置換パラメータの数と置換する値の数が合わなかったりすると結果がおかしなことになるので、ちゃんと数を合わせましょう。

実際のところ、公式のドキュメントにもっと色々詳しく書いてあります。

bashのProcess Substitutionを利用したdiff

bashに Process Substitution(プロセス置換) という機能があるのを全然知りませんでした。

詳しい説明は別の方の記事を参照ください。。。

たとえば、この機能をdiffコマンドと組み合わせて使ったりすると効果的なようです。

diffは、入力対象としてファイルのみを対象としているため、通常のパイプで処理済みテキストを渡すことがでないのですが、
Process Substitutionを利用して、コマンドの処理結果同士を diff で比較することが可能です。

呼び出し方法は以下のようになります。

diff <(なんかのコマンド1) <(なんかのコマンド2)


例えば以下の2つのファイルがあったとして、重複行は1行にまとめた上で、データに差分があるかないかをチェックしたいとします。
33333 という行が sample1.txt にだけ存在するという差分があります)


■sample1.txt

00000
11111
11111
12345
12346
11111
22222
33333
44444
55555
66666
77777
88888
99999
00000
12345
12345
11111
99999
00000
11111
22222
33333
44444
55555
66666
77777
88888
99999
00000
12345
12345
12346
11111
23456


■sample2.txt

00000
11111
11111
12345
11111
22222
44444
55555
66666
77777
88888
99999
00000
12345
12345
11111
99999
00000
11111
22222
44444
77777
88888
99999
00000
12345
12346
11111
23456


通常であれば以下のような処理手順になると思います。

$sort sample1.txt | uniq > sample1.txt.tmp
$sort sample2.txt | uniq > sample2.txt.tmp
$diff sample1.txt.tmp sample2.txt.tmp
7d6
< 33333

一度、sortuniqコマンドを利用して中間ファイルを作り出して、その中間ファイル同士をdiffで比較します。


これを、Process Substitutionを利用してやると以下のようになります。

$diff <(sort sample1.txt | uniq) <(sort sample2.txt | uniq)
7d6
< 33333

なんということでしょう、中間ファイルが不要となっております!。


今後、Process Substitution が利用できる場面では、どんどん使っていきたいです。

例外のスタックトレースが出力されなくなる

Javaアプリケーションを実行していると、ずっと出力できていた例外(Exception)のスタックトレース(StackTrace)が出力されなくなる場合があります。
気づいてみたら、あれ?ログに例外のスタックトレースが出ていない! というような状況に出くわすことが稀にあったりします。

同じスタックトレースを何度も何度も出力していると、HotSpot VMの最適化が適用されて本現象が発生する様です。

HotSpot VMの実行時最適化の一環で、繰り返し出力される一部の組み込み例外では、
同じインスタンスを使い回すことでインスタンス生成コストを抑える処理が行われる様です。
使いまわされる例外のインスタンスは、他の場所ででthrowされた例外の情報が混入しないように、スタックトレースそのものが省略されるようです。

これを抑止するためのVMオプションが -XX:-OmitStackTraceInFastThrow です。

このオプションを指定すると、この最適化が行われなくなり、スタックトレースが出ないということは無くなります。

サンプルで試してみましょう。


基本的にひたすらNullPointerExceptionのスタックトレースをログ出力するサンプルになっています


(1) 数回NullPointerExceptionのスタックトレースを出力する

繰り返し3回だけNullPointerExceptionのスタックトレースをログ出力します

■実行用プログラム

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class OmitExceptionSample {

    private static final Logger logger = LoggerFactory.getLogger(OmitExceptionSample.class);

    private static String nullString = null;

    public static void main(String[] args) {
        for (int i = 0; i < 3; i++) {
            traceNulPointerException(i);
        }

    }

    private static void  traceNulPointerException(int index) {
        logger.info("call traceNulPointerException {}", index);
        try {
            int length = nullString.length();
        } catch (NullPointerException e) {
            logger.warn("Caught Exception.", e);
        }
    }
}


■実行結果

16:41:32.922 [main] INFO net.yyuki.exception.OmitExceptionSample - call traceNulPointerException 0
16:41:32.932 [main] WARN net.yyuki.exception.OmitExceptionSample - Caught Exception.
java.lang.NullPointerException: null
    at net.yyuki.exception.OmitExceptionSample.traceNulPointerException(OmitExceptionSample.java:22)
    at net.yyuki.exception.OmitExceptionSample.main(OmitExceptionSample.java:14)
16:41:32.933 [main] INFO net.yyuki.exception.OmitExceptionSample - call traceNulPointerException 1
16:41:32.933 [main] WARN net.yyuki.exception.OmitExceptionSample - Caught Exception.
java.lang.NullPointerException: null
    at net.yyuki.exception.OmitExceptionSample.traceNulPointerException(OmitExceptionSample.java:22)
    at net.yyuki.exception.OmitExceptionSample.main(OmitExceptionSample.java:14)
16:41:32.933 [main] INFO net.yyuki.exception.OmitExceptionSample - call traceNulPointerException 2
16:41:32.933 [main] WARN net.yyuki.exception.OmitExceptionSample - Caught Exception.
java.lang.NullPointerException: null
    at net.yyuki.exception.OmitExceptionSample.traceNulPointerException(OmitExceptionSample.java:22)
    at net.yyuki.exception.OmitExceptionSample.main(OmitExceptionSample.java:14)

スタックトレースが出力され続けています。


(2) 10万回NullPointerExceptionのスタックトレースを出力する

繰り返し10万回NullPointerExceptionのスタックトレースをログ出力します

■実行用プログラム

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class OmitExceptionSample {

    private static final Logger logger = LoggerFactory.getLogger(OmitExceptionSample.class);

    private static String nullString = null;

    public static void main(String[] args) {
        for (int i = 0; i < 100000; i++) {
            traceNulPointerException(i);
        }

    }

    private static void  traceNulPointerException(int index) {
        logger.info("call traceNulPointerException {}", index);
        try {
            int length = nullString.length();
        } catch (NullPointerException e) {
            logger.warn("Caught Exception.", e);
        }
    }
}


■実行結果

16:43:14.822 [main] INFO net.yyuki.exception.OmitExceptionSample - call traceNulPointerException 0
16:43:14.822 [main] WARN net.yyuki.exception.OmitExceptionSample - Caught Exception.
java.lang.NullPointerException: null
    at net.yyuki.exception.OmitExceptionSample.traceNulPointerException(OmitExceptionSample.java:22)
    at net.yyuki.exception.OmitExceptionSample.main(OmitExceptionSample.java:14)
16:43:14.823 [main] INFO net.yyuki.exception.OmitExceptionSample - call traceNulPointerException 1
16:43:14.823 [main] WARN net.yyuki.exception.OmitExceptionSample - Caught Exception.
java.lang.NullPointerException: null
    at net.yyuki.exception.OmitExceptionSample.traceNulPointerException(OmitExceptionSample.java:22)
    at net.yyuki.exception.OmitExceptionSample.main(OmitExceptionSample.java:14)

(中略)

16:43:15.753 [main] INFO net.yyuki.exception.OmitExceptionSample - call traceNulPointerException 99996
16:43:15.753 [main] WARN net.yyuki.exception.OmitExceptionSample - Caught Exception.
java.lang.NullPointerException: null
16:43:15.753 [main] INFO net.yyuki.exception.OmitExceptionSample - call traceNulPointerException 99997
16:43:15.753 [main] WARN net.yyuki.exception.OmitExceptionSample - Caught Exception.
java.lang.NullPointerException: null
16:43:15.753 [main] INFO net.yyuki.exception.OmitExceptionSample - call traceNulPointerException 99998
16:43:15.753 [main] WARN net.yyuki.exception.OmitExceptionSample - Caught Exception.
java.lang.NullPointerException: null
16:43:15.753 [main] INFO net.yyuki.exception.OmitExceptionSample - call traceNulPointerException 99999
16:43:15.753 [main] WARN net.yyuki.exception.OmitExceptionSample - Caught Exception.
java.lang.NullPointerException: null

最初はスタックトレースが出力さていますが、後半出力されなくなっています。


(3) -XX:-OmitStackTraceInFastThrowを指定する。

-XX:-OmitStackTraceInFastThrowをVMオプションに指定して、実行してみます。10万回NullPointerExceptionのスタックトレースを出力します。

実行用のプログラムは、(2)と同じです

■実行結果

16:43:04.722 [main] INFO net.yyuki.exception.OmitExceptionSample - call traceNulPointerException 0
16:43:04.722 [main] WARN net.yyuki.exception.OmitExceptionSample - Caught Exception.
java.lang.NullPointerException: null
    at net.yyuki.exception.OmitExceptionSample.traceNulPointerException(OmitExceptionSample.java:22)
    at net.yyuki.exception.OmitExceptionSample.main(OmitExceptionSample.java:14)
16:43:04.723 [main] INFO net.yyuki.exception.OmitExceptionSample - call traceNulPointerException 1
16:43:04.723 [main] WARN net.yyuki.exception.OmitExceptionSample - Caught Exception.
java.lang.NullPointerException: null
    at net.yyuki.exception.OmitExceptionSample.traceNulPointerException(OmitExceptionSample.java:22)
    at net.yyuki.exception.OmitExceptionSample.main(OmitExceptionSample.java:14)

(中略)

16:47:08.694 [main] INFO net.yyuki.exception.OmitExceptionSample - call traceNulPointerException 99996
16:47:08.694 [main] WARN net.yyuki.exception.OmitExceptionSample - Caught Exception.
java.lang.NullPointerException: null
    at net.yyuki.exception.OmitExceptionSample.traceNulPointerException(OmitExceptionSample.java:22)
    at net.yyuki.exception.OmitExceptionSample.main(OmitExceptionSample.java:14)
16:47:08.694 [main] INFO net.yyuki.exception.OmitExceptionSample - call traceNulPointerException 99997
16:47:08.694 [main] WARN net.yyuki.exception.OmitExceptionSample - Caught Exception.
java.lang.NullPointerException: null
    at net.yyuki.exception.OmitExceptionSample.traceNulPointerException(OmitExceptionSample.java:22)
    at net.yyuki.exception.OmitExceptionSample.main(OmitExceptionSample.java:14)
16:47:08.694 [main] INFO net.yyuki.exception.OmitExceptionSample - call traceNulPointerException 99998
16:47:08.694 [main] WARN net.yyuki.exception.OmitExceptionSample - Caught Exception.
java.lang.NullPointerException: null
    at net.yyuki.exception.OmitExceptionSample.traceNulPointerException(OmitExceptionSample.java:22)
    at net.yyuki.exception.OmitExceptionSample.main(OmitExceptionSample.java:14)
16:47:08.694 [main] INFO net.yyuki.exception.OmitExceptionSample - call traceNulPointerException 99999
16:47:08.694 [main] WARN net.yyuki.exception.OmitExceptionSample - Caught Exception.
java.lang.NullPointerException: null
    at net.yyuki.exception.OmitExceptionSample.traceNulPointerException(OmitExceptionSample.java:22)
    at net.yyuki.exception.OmitExceptionSample.main(OmitExceptionSample.java:14)

最後までスタックトレースが出力さています。


まとめ

組み込み例外のスタックトレースを何度も出力しなければならないが、そのスタックトレースが出なくなるのを抑止したい場合は、
-XX:-OmitStackTraceInFastThrow の VMオプション を付与しましょう。