【Golang】Go言語でjsonを扱う

「Goプログラミング実践入門 標準ライブラリでゼロからWebアプリを作る」を読んでいたら、jsonを扱う項目があったので練習がてら自分でも書いてみました。

ほかにもやり方はあるようですが、まずはオーソドックスなやり方のencoding/json使ってやってみます。

ざっくり言うとこんな感じ。

  • Read
    • jsonの構造に沿って、Go側で構造体を作る。
    • json.Unmarshalで分解。
  • Write
    • 作りたいjsonの内容を構造体で書く。
    • json.MarshalIndentで読み込む。
    • ファイルに書きだす。

ソースコード

gistにあげてみました。

  • json_sample.jsonとjson_read_write.goをローカルに置いておきます。
  • プログラムを実行すると「03 program result」の結果が出力されて、json_output.jsonが作られます(はず!)。


Golangでjsonを扱う

Marshalについて

Marshalには2種類あって、json.Marsharlとjson.MarshalIndentがあるようです。

json.Marshal

https://golang.org/pkg/encoding/json/#Marshal
json.Marshalは単純にjson作るだけみたいです。やってみると下記のように1行で全部出力されました。

{"id":11111,"author":"toriyama akira","content":"","comment":{"comment_id":999999,"message":"sugeeeeeee"},"books":[{"book_id":1004,"title":"naushika"},{"book_id":2006,"title":"akira"},{"book_id":4005,"title":"inachu"}]}[

json.MarshalIndent

https://golang.org/pkg/encoding/json/#MarshalIndent
json.MarshalIndentはprefixとindentが指定できます。

func MarshalIndent(v interface{}, prefix, indent string) ([]byte, error)

リンクの例の通りですが、こんな風に書くとこうなります。

output, err := json.MarshalIndent(&post_write, "<prefix>", "<indent>")
{
<prefix><indent>"id": 11111,
<prefix><indent>"author": "toriyama akira",
<prefix><indent>"content": "",
<prefix><indent>"comment": {
<prefix><indent><indent>"comment_id": 999999,
<prefix><indent><indent>"message": "sugeeeeeee"
<prefix><indent>},
<prefix><indent>"books": [
<prefix><indent><indent>{
<prefix><indent><indent><indent>"book_id": 1004,
<prefix><indent><indent><indent>"title": "naushika"
<prefix><indent><indent>},
<prefix><indent><indent>{
<prefix><indent><indent><indent>"book_id": 2006,
<prefix><indent><indent><indent>"title": "akira"
<prefix><indent><indent>},
<prefix><indent><indent>{
<prefix><indent><indent><indent>"book_id": 4005,
<prefix><indent><indent><indent>"title": "inachu"
<prefix><indent><indent>}
<prefix><indent>]
<prefix>}

つまづいたところ

構造体はあまり書いたことなかったんですね。
たぶん自分だけだと思いますが、しょーもないミスをしてました。

てきとーに書いて実行してたらいろいろエラーがでました。
こんな感じ

# command-line-arguments
./json_read_write.go:55:26: syntax error: unexpected newline, expecting comma or }
./json_read_write.go:60:23: syntax error: unexpected newline, expecting comma or }

Go言語の構造体って最後の要素にもカンマが必要なんですね!うっかりしてた。

        post_write := Post {
                Id : 11111,
                Author : "toriyama akira",
                Comment : Comment {
                        Comment_id : 999999,
                        Message : "sugeeeeeee",    // <----こことか!
                },
                Books : []Book {
                        Book {
                                Book_id : 1004,
                                Title : "naushika",   // <----こことか!
                        },
                        Book {
                                Book_id : 2006,
                                Title : "akira",    // <----こことか!
                        },
                        Book {
                                Book_id : 4005,
                                Title : "inachu",  // <----こことか!
                        },
                },       // <----こことか!
        }

コメント

他にもjson.NewEncoderでもできるみたい。後日調べてみよう。たぶん。

Goプログラミング実践入門 標準ライブラリでゼロからWebアプリを作る impress top gearシリーズ

Goプログラミング実践入門 標準ライブラリでゼロからWebアプリを作る impress top gearシリーズ

これはかなりいい本でした。
後日感想かかないとなあ。

centos 7にmysql clientを入れる

mysqlのクライアントがほしかったのでインストールtipsを書いておく。

centos 7 からmariadbなんですね。なんだかややこしいなあ。

インストールするサーバーにはHadoop関連のコマンドもいれてある。
単純にyum install mariadbをするとこんなエラーが出てしまった。

Transaction check error:
  file /usr/share/mysql/charsets/Index.xml from install of MariaDB-common-10.3.10-1.el7.centos.x86_64 conflicts with file from package mysql-community-common-5.7.16-1.el7.x86_64
  file /usr/share/mysql/charsets/armscii8.xml from install of MariaDB-common-10.3.10-1.el7.centos.x86_64 conflicts with file from package mysql-community-common-5.7.16-1.el7.x86_64
................................

Hadoop関連のhadoop, hive, parquet コマンドらへんはmysql-community-commonを使ってるみたい。


なので仕方ないのでmysql クライアントをrpm からダウンロードしてインストールした。

gistcf686beaa9642ac59cc85487a00a4148

うまくいった。

JenkinsのSlaveノードの冗長化を考えてみた

f:id:suganoo:20181015183735p:plain
Jenkinsを構築しているんですが、障害対策を検討してみたお話です。

自分ところで使ってるJenkinsはそれほどクリティカルではないにせよ、Jenkinsのノードが落ちてしまったりするとリカバリがなかなか大変なので障害対策をしておきたかったわけです。

Masterに関しては、Docker上で動かしてイメージをエクスポートしてバックアップしておき復旧をお手軽にしておいた。

そんでSlave側ノード、つまり接続先が何かしらで応答しなくなった時どうしよっか?と考えて、対処tipsを書いておこうと思いました

何をしたいのか

  • 設定が全く同じSlaveノードを2台用意してある。(slave01, slave02とする)
  • 通常はslave01を使う。
  • 接続先のSlave01ノードが落ちてた場合、すぐに別の冗長化したSlave02ノードに接続してジョブを実行してもらいたい。

f:id:suganoo:20181015170343p:plain

これを考えた時、LBで振り分けるか、DNSで死活監視してIPを書きかえるか、を考えたけどめんどくさくなりそうなのでやめた。

  • LBで振り分ける
    • 書いてなかったけど、Jenkinsはaws EC2上でSlaveはオンプレ。ELB使おうと思ったけど、ELBはオンプレのIPを振り分けられない。
    • ALBとかほかのサービスとか、LBサーバー建てるかとか、考えたけど管理するものを増やしたくなかったのでボツ。
  • DNSで振り分ける
    • 監視して振り分けようかと思ったけど、これもそこまでDNS使う必要あるか?と思ってやめた。
    • また、監視スクリプトとかもDNSに紐づいてると、こちらも管理が増えそうだったのでやりたくなかった。

ちなみにだけどプラグインでそういうことができるものがあるか調べたのだけど、どうもやりたいことを実現できそうなプラグインが見つからなかった。

どうやって解決したか

プロジェクトの設定にある「実行するノードを制限」のラベル式を使ったのと、Jenkinsのapiを使ってノードをオンライン/オフラインで切り替えてみた。

ラベル式

プロジェクト設定の「実行するノードを制限」のラベル式を使ってみた。
f:id:suganoo:20181015181952p:plain
このラベル式はなかなか曲者で、これ使えば意図通りにできるんじゃないの!?っと淡い期待をした。
けども、いろいろ試した結果ラベル式はよくわからなかった。。。。

けども試したところ、|| (ラベルのOR条件)は使えそうとわかったのでOR条件を使うことにした。

ラベル式に(!hoge)とかhoge && fuga とか指定できるけど、正直振る舞いがよくわからない。
良くおできになるエンジニアの方は頑張って調査してみてほしいです。

ちなみに

ちなみに||でつなぐとこうなりました。

実行するノードを確認のため、ジョブで実行するシェルスクリプトにhostnameを実行し実行ノードを確認しています。

実行するノードのラベル式 実行ノード
slave01 || slave02 slave02
slave02 || slave01 slave02
hoge || slave02 || slave01 slave02

なぜslave02が優先されるのかはわからなかった。
名前順なのか?、接続レスポンスが短い順?かと思ったけどそうでもなさそう。わからんーー!

ですが、ノードのオフライン条件を加えると意図通りになった。

ラベル式 slave01の状態 slave02の状態 実行ノード
slave01 || slave02 online offline slave01
slave01 || slave02 offline online slave02

これを使おうというわけです。

Slaveのオンライン/オフラインの切り替え

探してみたところ切り替え用のapiがあるようです。ラッキー!!

下記のようにcurlを実行するとSlaveノードのオンライン/オフラインが切り替えられる。

curl -s -XPOST --user (user):(apitokenxxxx) 'http://localhost:8080/computer/slave02/toggleOffline'

APIトークンですが、jenkinsの画面の右上にある「ユーザー→設定」で下記のようにAPIトークンが取得できます。
f:id:suganoo:20181015181906p:plain
APIトークンは一回しか表示されないから注意!

またオフラインの状態確認は下記のcurlで取得できます。

curl -s -XGET --user (user):(apitokenxxxx) 'http://localhost:8080/computer/slave02/api/json?pretty=true'

結果は省略しますが、こんな感じの結果が取得できます。

{
  "_class": "hudson.slaves.SlaveComputer",
  "actions": [],
  "assignedLabels": [
    {
      "name": "slave02"
    }
........
  "offline": false,
........

この"offline"キーで状態が取れるので、それをもとにしてオンライン/オフラインを切り替えることにした。
"offline":falseオンライン状態
"offline":true オフライン状態
(間違えそうだー)

ちなみにですが、"temporarilyOffline"というのもあります。
これはノード設定の画面から「このノードを一時的にオフラインにする」を押すと"temporarilyOffline":trueになる。

例えばなにかしらの理由でslave01が使えなくなった時を想定して、slave01のremote.jarプロセスを全部killしてみると、"offline":trueだけど"temporarilyOffline":falseになります。
なので"offline"で判断したほうがよさげ。

ジョブの設定と監視

ジョブの設定

ジョブ側の設定については「実行するノードを制限」のラベル式を「slave01 || slave02」にするだけです。

監視側

  • 定常状態をslave01:オンライン、slave02:オフラインにしておきます。
  • apiで取得できる"offline"キーを定期的に監視します。
  • slave01がオフラインになってたらslave02をオンラインに復活させます。

これでジョブをなるべく止めることなく動かすようにしてみた。

監視のスクリプトは省略。

最後に

良く調べたらtoggleOfflineだけじゃなくてdoDisconnectやlaunchSlaveAgentもあるみたいですね。
stackoverflow.com


状態にかかわらず一方的にオフライン/オンラインできるならこれの方がいいかも。


オンライン/オフラインって言葉間違えてないかな,.......

【プログラミング】codewarsがすんごくいい教材だった

f:id:suganoo:20181010185308p:plain


twitterでフォローしてる @yuki_sato さんから(勝手に)知ったのですが、とてもいいプログラミング学習サイトを知りました。

codewars
https://www.codewars.com

どんな人使うといいの?

ざっくりいうと、初級者競プロのプログラミングの課題サイトって感じでしょうか。

progateなどのようにプログラミングを0から学ぶスタイルではありません。

すでにある程度、なんとかググりながらコーディングできるレベル、の人が使うといいでしょう。

対応言語がいっぱいある!

驚いたのですが、学べる言語がかなり豊富です。

Java, ruby, python, などの言語は対応してるんですが、Haskell, F, F#, solidity...まで対応してるんですよ!
(問題数にかたよりはあると思いますが。。)

自分はjavascriptを学びたいのでjavascriptやってます。

回答するとベストプラクティスが出る

またもう一ついいことに、課題を解くとベストプラクティスが出るんですね。
これは学ぶ上でかなり助かります。

例えばこれ

  • ある数値が与えられる。その数値を2進数で表す時の1の数を返しなさい。
  • ex. 5 → "101" → 2、 7 → "111" → 3

自分が書いたコードはこれです。

var countBits = function(n) {
  // Program Me
  var num_one = 0;
  while ( 0 < n ) {
    if ( n % 2 == 1 ) {
      num_one++;
    }
    n = Math.floor( n / 2 );
  }
  return num_one;
};

ですが、ベストプラクティスだとなんと1行でできます。

countBits = n => n.toString(2).split('0').join('').length;

おおーすごい!

最後

こういうベストプラクティスが出るのはありがたいですわ。

知らなけらばどうしてたってわからないですもん。


コツコツやってみようと思います。

【beeline】Required field 'client_protocol' is unset!

beelineでHadoopにつなごうとしたらこんなエラーがでて困った。

18/10/10 15:59:41 [main]: ERROR jdbc.HiveConnection: Error opening session
org.apache.thrift.TApplicationException: Required field 'client_protocol' is unset! Struct:TOpenSessionReq(client_protocol:null, configuration:{use:database=default, set:hiveconf:hive.server2.thrift.resultset.default.fetch.size=1000})

その時の解決方法。

条件とやりたいこと

やりたいこと

  • すでにHadoopクラスターができている。
  • そのクラスターに対して新しいノードからクライアントしてbeelineを使いたかった。

条件など

  • Hadoopはclouderaを使っている。
  • エラーが出た時、Hiveはapache hive からダウンロードして使っていた。

ちなみにhive 1.2.2も2.3.3も3.1.0も使ってみたが、どのバージョンも同じようなエラーだった。

解決方法

cloudera からHiveをインストールする!

stackoverflowなどをみて解決方法を探ってたら
「hive-jdbc-1.2...だとかバージョン落としてみたら」とか
「metasrore_dbの場所が違うんじゃ?」とか出てきたけど
全然関係なかった。

cloudera のHiveを使えば解決しました。

sudo su -

# OSのバージョンは適宜変更してね
wget http://archive.cloudera.com/cdh5/redhat/7/x86_64/cdh/cloudera-cdh5.repo


# clouderaのバージョンが異なるのであれば変えておくこと。
vi cloudera-cdh5.repo

# ex.
# -------------------------------------------------------
baseurl=https://archive.cloudera.com/cdh5/redhat/7/x86_64/cdh/5/
↓
baseurl=https://archive.cloudera.com/cdh5/redhat/7/x86_64/cdh/5.15.0/
# -------------------------------------------------------

mv cloudera-cdh5.repo /etc/yum.repos.d/

yum install hive

これでうまくいった。

依存関係でhadoopコマンドやhdfsコマンドもインストールされるのね。

「HTMLとCSSで基礎から学ぶJavaScript」を読んでみた

HTMLとCSSで基礎から学ぶJavaScript

HTMLとCSSで基礎から学ぶJavaScript

しばらく前に読んだので更新しておく。

Javascriptを学びたくて買ってみました。

感想としてはうーん...という感じ。


初心者向けの本なのですが、説明が多くて文章がいっぱいあり読むのがつらくなってしまいました。

内容も古くなっており、中古だったからしょうがないんですけどね、最近のHTML5などには対応してなさそう。


もっとほかにいい本があるだろう。

「いちばんよくわかるHTML5&CSS3デザインきちんと入門」を読んでみた

いちばんよくわかるHTML5&CSS3デザインきちんと入門 (Design&IDEA)

いちばんよくわかるHTML5&CSS3デザインきちんと入門 (Design&IDEA)

こんな本を読んでみました。

仕事では使わないのですが、やっぱりWebサービスを作ってみたいなという熱が出てきました。
そこでamazonを物色したりフロントエンド関連のブログを探したところ、これに行きつきました。

感想としては、かなりいい本でした。

仕事柄フロントエンドの知識ってネットに頼るしかないんですよね。
ですが、この本を読むことで体系的なHTML、CSSの知識がついてかなり満足です。

パンくずリスト、flex-boxのやり方、divやspanの使い方など
あーこうやって作るんだー!と理解できるところが多くてよかったです。


自分がWebサイトを作るとしたら不得意なCSSとかにはエネルギーを使わず、bootstrapみたいなツールを使うと思います。
ですが、それがどうやって表現されているのか?に理解があるとちょっとした修正がしやすくなったり、設計がへんてこりんにならなかったりするメリットがあると思います。

うーんかなりいい本でした。


(こっちの本もよかったです)
suganoo.hatenablog.com

【Solidity】CryptoZombiesはブロックチェーンの勉強にむちゃくちゃいい教材だ!【Blockchain】

f:id:suganoo:20181001171524p:plain
cryptozombies.io

ここしばらく昼休みにちょこちょこCryptoZombiesをやってたのですが、すごくいい教材でした。

何が学べるのか

ざっとピックアップしてみますが、こんな感じでした。

  • Solidity contractの書き方
  • 各種関数修飾子の使い方
  • ゲームアプリケーションでの使い方
  • ERC721規格について
  • オーバーフロー、アンダーフローの対策
  • フロントエンドからweb3.jsの使い方

などなど。
Ethereum, Solidityの知識が身に付きます。

正直課題をこなしてるだけになり意味の理解が手薄になってしまい、上に書いた以上のこともあったかもしれません。
ですがかなり内容は網羅されていると思います。

話し言葉が楽しかった

どうでもいいところなのですが、説明するときの話し言葉がなかなか楽しいんですよね。

レッスン 2までよくぞたどり着いた!

このレッスン 2では、人間に噛み付いてゾンビ軍団を倍増させる方法を教えてやるが、怖がらずにしっかり学ぶのだ。

なんかこう、よくあるRPG的にプログラミングを学ばす感じでね。

各国言語にやくされてるみたいなので、どなたか日本語版をがんばったんだなーとよくわかります。

学ぶのが楽しくなります!

感想

アプリケーションとして使うための基礎的な知識が学べたのではと思います。
実践的にHTML, javascriptを含めてweb3.js, solidityが学べるのはほんとによかったです。

正直後半1/3くらいからややこしくなってきて、こなしてるだけになってしまいました。
なので今は復習してます。

これをやるとフロントエンドの知識ないのですが、がぜんやる気になってしまいました。

レッスンは今のところ(2018/10/01現在)6レッスンまでで、今後増える様子です。
アップデートが楽しみだなあ。

CryptoZombies blockchainを学ぶにはほんとおすすめです。

この本もおすすめ!

ブロックチェーンアプリケーション開発の教科書

ブロックチェーンアプリケーション開発の教科書

【メモ】sshd_configの修正は気をつけろ!最悪ログインできなくなる。

またアホなことやっちまった。。。

sshd_configをいじってたら、ログインできなくなっちまいました。

誰かが同じ轍をふまないように、自分のアホ操作をさらしておきます。

はぁー、EC2インスタンスだったし、デプロイもすぐできるようにしてたのがせめてもの救いでした。


sshd_configの修正はログインできなくなることもあるから気をつけろ!!!

前提条件

自分とこの環境はEC2をコンソールなどでつくるのではなく、それに接続したクラウドサービス経由でインスタンス作ってます。
そのサービスの中で独自にスクリプトを書くことができ、公開鍵まで配置してくれるようにしています。
自分のユーザーは管理者が作っててやたらめったら変更などできません。

なのでどんなインスタンスを作っても、自分の秘密鍵でローカルPCからすぐにsshログインできるようになっています。

はい、もう一回言います。

公開鍵認証でローカルPCからsshログインしていました。パスワードは設定していません。

なにをしたかったのか?

EC2のインスタンスを建てて、特定のユーザー(hogeユーザー)でdocker コンテナや別のインスタンスからログインできるようにしたかったわけです。
パスワード認証で。

インスタンスは作りなおすこともあるので公開鍵認証にしてると再度公開鍵の配置が煩わしいと思ったのでパスワード認証にしてました。

修正方法は?

※実際にコピペして有効にするなよ!やるときはちゃんと考えろよ!

パスワード認証にするには/etc/ssh/sshd_configに下記を書いて有効にします。

PasswordAuthentication yes

書いたらsshdをリロードして反映させましょう。

systemctl reload sshd

修正したらどうなった?

はい、これで別インスタンスからhogeユーザーとしてパスワード認証でsshログインできてめでたしめでたし!
っと思ってログアウトしてみました。


再度ローカルPCからログインしてみると、なんとパスワードを聞かれてログインできない!
最初のログインユーザーではパスワード設定してないので、なんにも対処のしようがありません。\(^o^)/オワタ

まとめ

しかたないのでインスタンスを作り直してどうにかしました。
EC2インスタンスだったこと、まだ中身にはなんも入れてなかったことがせめてもの救いでした。

  • sshd_configの修正はほんとに気を付けよう。
  • ansibleでもシェルスクリプトでも、さっとデプロイできる(復旧できる)操作を作っておいたほうがいいよ。

【Solidity】msg.senderってなに?

solidityを勉強してると、実行を自分のオーナー(?)に限定にするためにこんな書き方をすることがあります。

require(msg.sender == owner)

このmsg.senderは自分で定義してるわけではないので、最初のうちは

どっからこれは来てるんだ???

と戸惑います。


調べてみるとわかりました。
グローバルネームスペースですでに定義されてるやつだったんですね。

同じような質問がstackoverflowにありました。
stackoverflow.com

solidityのドキュメントに書いてあります。ほかにもいろいろありますね。

Units and Globally Available Variables — Solidity 0.4.26 documentation

Block and Transaction Properties

  • block.blockhash(uint blockNumber) returns (bytes32): hash of the given block - only works for 256 most recent, excluding current, blocks - deprecated in version 0.4.22 and replaced by blockhash(uint blockNumber).
  • block.coinbase (address payable): current block miner’s address
  • block.difficulty (uint): current block difficulty
  • block.gaslimit (uint): current block gaslimit
  • block.number (uint): current block number
  • block.timestamp (uint): current block timestamp as seconds since unix epoch
  • gasleft() returns (uint256): remaining gas
  • msg.data (bytes): complete calldata
  • msg.gas (uint): remaining gas - deprecated in version 0.4.21 and to be replaced by gasleft()
  • msg.sender (address payable): sender of the message (current call)
  • msg.sig (bytes4): first four bytes of the calldata (i.e. function identifier)
  • msg.value (uint): number of wei sent with the message
  • now (uint): current block timestamp (alias for block.timestamp)
  • tx.gasprice (uint): gas price of the transaction
  • tx.origin (address payable): sender of the transaction (full call chain)

【Blockchain】【Ethereum】【メモ】Ethereumの情報メモ

※随時更新予定(たぶん。。。)

Ethereumホワイトペーパー

ここのリポジトリを漁ればだいたいのものは入手できそう。
github.com

Tutorial

CryptoZombie

わかりやすい。けっこう楽しい。
cryptozombies.io

【Golang】userパッケージを使ってみる

userパッケージを使ってみました。

user - The Go Programming Language

package main

import (
        "fmt"
        "os/user"
)

func main() {
        user, err := user.Current()
        if err != nil {
                panic(err)
        }
        fmt.Println("User.Name : " + user.Name)
        fmt.Println("User.Uid : " + user.Uid)
        fmt.Println("User.Gid : " + user.Gid)
        fmt.Println("User.Username : " + user.Username)
        fmt.Println("User.HomeDir : " + user.HomeDir)
}
User.Name :
User.Uid : 501
User.Gid : 503
User.Username : hoge
User.HomeDir : /home/hoge

ドキュメントにあるようにUser.Nameはブランクのようです。

【シェルスクリプト】visudoでスクリプトから/etc/sudoersを編集する。

あるユーザー(foobar)ユーザーを作ったからsudo権限をつけたい。
それをスクリプトから実行したい。

としたとき、どうすればいいか?

ちょっと悩みました。

/etc/sudoersは直接編集できないし。。。
visudo でなにかしらのインプットはできない感じだし。

そしたら素晴らしい解法がstackoverflowに投稿されていました。

stackoverflow.com

echo 'foobar ALL=(ALL:ALL) ALL' | sudo EDITOR='tee -a' visudo

天才かよっ!


無事解決できました。

【Golang】runtimeを調べてみた

Go言語のruntimeはOSやプロセスの情報を得ることができます。
runtime - The Go Programming Language


CPU情報はDeprecatedになってしまったようですね。

下記のサンプルコードをもとにちょっと自分でも書いてみました。
golangcode.com

package main

import (
        "runtime"
        "fmt"
        "time"
)

func main() {
        fmt.Println("--- Params ---")
        fmt.Printf("GOROOT = %v\n",runtime.GOROOT())
        fmt.Printf("NumCPU = %v\n",  runtime.NumCPU())
        fmt.Printf("NumGoroutine = %v\n",  runtime.NumGoroutine())

        fmt.Println("--- memory test ---")
        fmt.Println("--- before ---")
        PrintMemUsage()
        fmt.Println("--- start ---")
        var mem_alloc [][]int
        for i := 0 ; i < 4 ; i++ {
                a := make([]int, 0, 999999)
                mem_alloc = append(mem_alloc, a)

                PrintMemUsage()
                time.Sleep(time.Second)
        }
        PrintMemUsage()
        fmt.Println("--- After GC ---")
        runtime.GC()
        PrintMemUsage()

}

func PrintMemUsage() {
        var m runtime.MemStats
        runtime.ReadMemStats(&m)

        fmt.Printf("Alloc = %v MiB\t", bToMb(m.Alloc))
        fmt.Printf("TotalAlloc = %v MiB\t", bToMb(m.TotalAlloc))
        fmt.Printf("Sys = %v MiB\t", bToMb(m.Sys))
        fmt.Printf("Mallocs = %v MiB\t", bToMb(m.Mallocs))
        fmt.Printf("Frees = %v MiB\t", bToMb(m.Frees))
        fmt.Printf("HeapAlloc = %v MiB\t", bToMb(m.HeapAlloc))
        fmt.Printf("HeapSys = %v MiB\t", bToMb(m.HeapSys))
        fmt.Printf("NumGC = %v", m.NumGC)
        fmt.Printf("\n")
}

func bToMb(b uint64) uint64 {
        return b / 1024 / 1024
}

こんな結果が取れます。

--- Params ---
GOROOT = /opt/go
NumCPU = 1
NumGoroutine = 1
--- memory test ---
--- before ---
Alloc = 0 MiB   TotalAlloc = 0 MiB      Sys = 1 MiB     Mallocs = 0 MiB Frees = 0 MiB   HeapAlloc = 0 MiB       HeapSys = 0 MiB NumGC = 0
--- start ---
Alloc = 7 MiB   TotalAlloc = 7 MiB      Sys = 11 MiB    Mallocs = 0 MiB Frees = 0 MiB   HeapAlloc = 7 MiB       HeapSys = 8 MiB NumGC = 1
Alloc = 15 MiB  TotalAlloc = 15 MiB     Sys = 19 MiB    Mallocs = 0 MiB Frees = 0 MiB   HeapAlloc = 15 MiB      HeapSys = 16 MiB        NumGC = 2
Alloc = 22 MiB  TotalAlloc = 22 MiB     Sys = 26 MiB    Mallocs = 0 MiB Frees = 0 MiB   HeapAlloc = 22 MiB      HeapSys = 23 MiB        NumGC = 3
Alloc = 30 MiB  TotalAlloc = 30 MiB     Sys = 34 MiB    Mallocs = 0 MiB Frees = 0 MiB   HeapAlloc = 30 MiB      HeapSys = 31 MiB        NumGC = 4
Alloc = 30 MiB  TotalAlloc = 30 MiB     Sys = 34 MiB    Mallocs = 0 MiB Frees = 0 MiB   HeapAlloc = 30 MiB      HeapSys = 31 MiB        NumGC = 4
--- After GC ---
Alloc = 0 MiB   TotalAlloc = 30 MiB     Sys = 34 MiB    Mallocs = 0 MiB Frees = 0 MiB   HeapAlloc = 0 MiB       HeapSys = 31 MiB        NumGC = 5